Compare commits

..

No commits in common. "master" and "migrate2efcore" have entirely different histories.

156 changed files with 1503 additions and 11879 deletions

View file

@ -1,469 +1,450 @@
; EditorConfig to support per-solution formatting. # Version: 4.1.1 (Using https://semver.org/)
; Use the EditorConfig VS add-in to make this work. # Updated: 2022-05-23
; http://editorconfig.org/ # See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
; # See https://github.com/RehanSaeed/EditorConfig for updates to this file.
; Here are some resources for what's supported for .NET/C# # See http://EditorConfig.org for more information about .editorconfig files.
; https://kent-boogaart.com/blog/editorconfig-reference-for-c-developers
; https://learn.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
;
; Be **careful** editing this because some of the rules don't support adding a severity level
; For instance if you change to `dotnet_sort_system_directives_first = true:warning` (adding `:warning`)
; then the rule will be silently ignored.
; This is the default for the codeline. ##########################################
# Common Settings
##########################################
# This file is the top-most EditorConfig file
root = true root = true
; For disabling MA0048 and MA0051 in a specific folder, e.g., Migrations # All Files
[**/Migrations/*.cs]
dotnet_diagnostic.MA0048.severity = none
dotnet_diagnostic.MA0051.severity = none
[*] [*]
indent_style = space
charset = utf-8 charset = utf-8
trim_trailing_whitespace = true indent_style = space
insert_final_newline = true
[*.cs]
dotnet_diagnostic.MA0004.severity = none
file_header_template = Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
indent_size = 4 indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
##########################################
# File Extension Settings
##########################################
# Visual Studio Solution Files
[*.sln]
indent_style = tab
# Visual Studio XML Project Files
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML Configuration Files
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
indent_size = 2
# JSON Files
[*.{json,json5,webmanifest}]
indent_size = 2
# YAML Files
[*.{yml,yaml}]
indent_size = 2
# Markdown Files
[*.{md,mdx}]
trim_trailing_whitespace = false
# Web Files
[*.{htm,html,js,jsm,ts,tsx,cjs,cts,ctsx,mjs,mts,mtsx,css,sass,scss,less,pcss,svg,vue}]
indent_size = 2
# Batch Files
[*.{cmd,bat}]
end_of_line = crlf
# Bash Files
[*.sh]
end_of_line = lf
# Makefiles
[Makefile]
indent_style = tab
##########################################
# Default .NET Code Style Severities
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope
##########################################
[*.{cs,csx,cake,vb,vbx}]
# Default Severity for all .NET Code Style rules below
dotnet_analyzer_diagnostic.severity = warning
##########################################
# Language Rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules
##########################################
# .NET Style Rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#net-style-rules
[*.{cs,csx,cake,vb,vbx}]
# "this." and "Me." qualifiers
dotnet_style_qualification_for_field = true:warning
dotnet_style_qualification_for_property = true:warning
dotnet_style_qualification_for_method = true:warning
dotnet_style_qualification_for_event = true:warning
# Language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Modifier preferences
dotnet_style_require_accessibility_modifiers = always:warning
csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:warning
visual_basic_preferred_modifier_order = Partial, Default, Private, Protected, Public, Friend, NotOverridable, Overridable, MustOverride, Overloads, Overrides, MustInherit, NotInheritable, Static, Shared, Shadows, ReadOnly, WriteOnly, Dim, Const, WithEvents, Widening, Narrowing, Custom, Async:warning
dotnet_style_readonly_field = true:warning
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning
# Expression-level preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_prefer_inferred_tuple_names = 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 = false:suggestion
dotnet_diagnostic.IDE0045.severity = suggestion
dotnet_style_prefer_conditional_expression_over_return = false:suggestion
dotnet_diagnostic.IDE0046.severity = suggestion
dotnet_style_prefer_compound_assignment = true:warning
dotnet_style_prefer_simplified_interpolation = true:warning
dotnet_style_prefer_simplified_boolean_expressions = true:warning
# Null-checking preferences
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
# File header preferences
# file_header_template = <copyright file="{fileName}" company="PROJECT-AUTHOR">\n© PROJECT-AUTHOR\n</copyright>
# If you use StyleCop, you'll need to disable SA1636: File header copyright text should match.
# dotnet_diagnostic.SA1636.severity = none
# Undocumented
dotnet_style_operator_placement_when_wrapping = end_of_line:warning
csharp_style_prefer_null_check_over_type_check = true:warning
# C# Style Rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules
[*.{cs,csx,cake}]
# 'var' preferences
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = true:warning
# Expression-bodied members
csharp_style_expression_bodied_methods = true:warning
csharp_style_expression_bodied_constructors = true:warning
csharp_style_expression_bodied_operators = true:warning
csharp_style_expression_bodied_properties = true:warning
csharp_style_expression_bodied_indexers = true:warning
csharp_style_expression_bodied_accessors = true:warning
csharp_style_expression_bodied_lambdas = true:warning
csharp_style_expression_bodied_local_functions = true:warning
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
csharp_style_prefer_switch_expression = true:warning
csharp_style_prefer_pattern_matching = true:warning
csharp_style_prefer_not_pattern = true:warning
# Expression-level preferences
csharp_style_inlined_variable_declaration = true:warning
csharp_prefer_simple_default_expression = true:warning
csharp_style_pattern_local_over_anonymous_function = true:warning
csharp_style_deconstructed_variable_declaration = true:warning
csharp_style_prefer_index_operator = true:warning
csharp_style_prefer_range_operator = true:warning
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
# "Null" checking preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning
# Code block preferences
csharp_prefer_braces = true:warning
csharp_prefer_simple_using_statement = true:suggestion
dotnet_diagnostic.IDE0063.severity = suggestion
# 'using' directive preferences
csharp_using_directive_placement = inside_namespace:warning
# Modifier preferences
csharp_prefer_static_local_function = true:warning
##########################################
# Unnecessary Code Rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/unnecessary-code-rules
##########################################
# .NET Unnecessary code rules
[*.{cs,csx,cake,vb,vbx}]
dotnet_code_quality_unused_parameters = all:warning
dotnet_remove_unnecessary_suppression_exclusions = none:warning
# C# Unnecessary code rules
[*.{cs,csx,cake}]
csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
dotnet_diagnostic.IDE0058.severity = suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
dotnet_diagnostic.IDE0059.severity = suggestion
##########################################
# Formatting Rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules
##########################################
# .NET formatting rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#net-formatting-rules
[*.{cs,csx,cake,vb,vbx}]
# Organize using directives
dotnet_sort_system_directives_first = true dotnet_sort_system_directives_first = true
dotnet_diagnostic.MA0007.severity = none dotnet_separate_import_directive_groups = false
#MA0004.report = DetectContext # (default) Try to detect the current context and report only if it considers ConfigureAwait is needed # Dotnet namespace options
# Don't use this. qualifier dotnet_style_namespace_match_folder = true:suggestion
dotnet_style_qualification_for_field = false:suggestion dotnet_diagnostic.IDE0130.severity = suggestion
dotnet_style_qualification_for_property = false:suggestion
# use int x = .. over Int32 # C# formatting rules
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#c-formatting-rules
[*.{cs,csx,cake}]
# use int.MaxValue over Int32.MaxValue # Newline options
dotnet_style_predefined_type_for_member_access = true:suggestion # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#new-line-options
# Require var all the time.
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
# Disallow throw expressions.
csharp_style_throw_expression = false:suggestion
# Newline settings
csharp_new_line_before_open_brace = all csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true csharp_new_line_before_else = true
csharp_new_line_before_catch = true csharp_new_line_before_catch = true
csharp_new_line_before_finally = true csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation options
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#indentation-options
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = no_change
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents_when_block = false
# Spacing options
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#spacing-options
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_after_comma = true
csharp_space_before_comma = false
csharp_space_after_dot = false
csharp_space_before_dot = false
csharp_space_after_semicolon_in_for_statement = true
csharp_space_before_semicolon_in_for_statement = false
csharp_space_around_declaration_statements = false
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false
# Wrap options
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#wrap-options
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
# Namespace options
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#namespace-options
csharp_style_namespace_declarations = file_scoped:warning
# Namespace settings ##########################################
csharp_style_namespace_declarations = file_scoped # .NET Naming Rules
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/naming-rules
##########################################
# Brace settings [*.{cs,csx,cake,vb,vbx}]
csharp_prefer_braces = true # Prefer curly braces even for one line of code
# name all constant fields using PascalCase ##########################################
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion # Styles
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields ##########################################
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field # camel_case_style - Define the camelCase style
dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_style.camel_case_style.capitalization = camel_case
# pascal_case_style - Define the PascalCase style
dotnet_naming_style.pascal_case_style.capitalization = pascal_case dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# first_upper_style - The first character must start with an upper-case character
# internal and private fields should be _camelCase dotnet_naming_style.first_upper_style.capitalization = first_word_upper
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion # prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field # prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T'
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
dotnet_naming_style.camel_case_underscore_style.required_prefix = _ dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case # disallowed_style - Anything that has this style applied is marked as disallowed
dotnet_naming_style.disallowed_style.capitalization = pascal_case
[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}] dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
indent_size = 2 dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file
# Xml config files dotnet_naming_style.internal_error_style.capitalization = pascal_case
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
indent_size = 2 dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____
[*.json] ##########################################
indent_size = 2 # .NET Design Guideline Field Naming Rules
# Naming rules for fields follow the .NET Framework design guidelines
[*.{ps1,psm1}] # https://docs.microsoft.com/dotnet/standard/design-guidelines/index
indent_size = 4 ##########################################
[*.sh] # All public/protected/protected_internal constant fields must be PascalCase
indent_size = 4 # https://docs.microsoft.com/dotnet/standard/design-guidelines/field
end_of_line = lf dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
[*.{razor,cshtml}] dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
charset = utf-8-bom dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style
[*.{cs,vb}] dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning
# SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time # All public/protected/protected_internal static readonly fields must be PascalCase
dotnet_diagnostic.SYSLIB1054.severity = warning # https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal
# CA1018: Mark attributes with AttributeUsageAttribute dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_diagnostic.CA1018.severity = warning dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group
# CA1047: Do not declare protected member in sealed type dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style
dotnet_diagnostic.CA1047.severity = warning dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning
# CA1305: Specify IFormatProvider # No other public/protected/protected_internal fields are allowed
dotnet_diagnostic.CA1305.severity = warning # https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal
# CA1507: Use nameof to express symbol names dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field
dotnet_diagnostic.CA1507.severity = warning dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style
# CA1510: Use ArgumentNullException throw helper dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error
dotnet_diagnostic.CA1510.severity = warning
##########################################
# CA1511: Use ArgumentException throw helper # StyleCop Field Naming Rules
dotnet_diagnostic.CA1511.severity = warning # Naming rules for fields follow the StyleCop analyzers
# This does not override any rules using disallowed_style above
# CA1512: Use ArgumentOutOfRangeException throw helper # https://github.com/DotNetAnalyzers/StyleCopAnalyzers
dotnet_diagnostic.CA1512.severity = warning ##########################################
# CA1513: Use ObjectDisposedException throw helper # All constant fields must be PascalCase
dotnet_diagnostic.CA1513.severity = warning # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
# CA1725: Parameter names should match base declaration dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const
dotnet_diagnostic.CA1725.severity = suggestion dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group
# CA1802: Use literals where appropriate dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = pascal_case_style
dotnet_diagnostic.CA1802.severity = warning dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning
# CA1805: Do not initialize unnecessarily # All static readonly fields must be PascalCase
dotnet_diagnostic.CA1805.severity = warning # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
# CA1810: Do not initialize unnecessarily dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_diagnostic.CA1810.severity = warning dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group
# CA1821: Remove empty Finalizers dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style
dotnet_diagnostic.CA1821.severity = warning dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning
# CA1822: Make member static # No non-private instance fields are allowed
dotnet_diagnostic.CA1822.severity = warning # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md
dotnet_code_quality.CA1822.api_surface = private, internal dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field
# CA1823: Avoid unused private fields dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group
dotnet_diagnostic.CA1823.severity = warning dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning # Private fields must be camelCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private
dotnet_diagnostic.CA1826.severity = warning dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group
# CA1827: Do not use Count() or LongCount() when Any() can be used dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = camel_case_style
dotnet_diagnostic.CA1827.severity = warning dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning
# CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used # Local variables must be camelCase
dotnet_diagnostic.CA1828.severity = warning # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md
dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local
# CA1829: Use Length/Count property instead of Count() when available dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local
dotnet_diagnostic.CA1829.severity = warning dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style
# CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = silent
dotnet_diagnostic.CA1830.severity = warning
# This rule should never fire. However, it's included for at least two purposes:
# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate # First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers.
dotnet_diagnostic.CA1831.severity = warning # Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#).
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = *
# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field
dotnet_diagnostic.CA1832.severity = warning dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style
# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error
dotnet_diagnostic.CA1833.severity = warning
# CA1834: Consider using 'StringBuilder.Append(char)' when applicable ##########################################
dotnet_diagnostic.CA1834.severity = warning # Other Naming Rules
##########################################
# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
dotnet_diagnostic.CA1835.severity = warning # All of the following must be PascalCase:
# - Namespaces
# CA1836: Prefer IsEmpty over Count # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces
dotnet_diagnostic.CA1836.severity = warning # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Classes and Enumerations
# CA1837: Use 'Environment.ProcessId' # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_diagnostic.CA1837.severity = warning # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Delegates
# CA1838: Avoid 'StringBuilder' parameters for P/Invokes # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types
dotnet_diagnostic.CA1838.severity = warning # - Constructors, Properties, Events, Methods
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members
# CA1839: Use 'Environment.ProcessPath' dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property
dotnet_diagnostic.CA1839.severity = warning dotnet_naming_rule.element_rule.symbols = element_group
dotnet_naming_rule.element_rule.style = pascal_case_style
# CA1840: Use 'Environment.CurrentManagedThreadId' dotnet_naming_rule.element_rule.severity = warning
dotnet_diagnostic.CA1840.severity = warning
# Interfaces use PascalCase and are prefixed with uppercase 'I'
# CA1841: Prefer Dictionary.Contains methods # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_diagnostic.CA1841.severity = warning dotnet_naming_symbols.interface_group.applicable_kinds = interface
dotnet_naming_rule.interface_rule.symbols = interface_group
# CA1842: Do not use 'WhenAll' with a single task dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
dotnet_diagnostic.CA1842.severity = warning dotnet_naming_rule.interface_rule.severity = warning
# CA1843: Do not use 'WaitAll' with a single task # Generics Type Parameters use PascalCase and are prefixed with uppercase 'T'
dotnet_diagnostic.CA1843.severity = warning # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter
# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream' dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group
dotnet_diagnostic.CA1844.severity = warning dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style
dotnet_naming_rule.type_parameter_rule.severity = warning
# CA1845: Use span-based 'string.Concat'
dotnet_diagnostic.CA1845.severity = warning # Function parameters use camelCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters
# CA1846: Prefer AsSpan over Substring dotnet_naming_symbols.parameters_group.applicable_kinds = parameter
dotnet_diagnostic.CA1846.severity = warning dotnet_naming_rule.parameters_rule.symbols = parameters_group
dotnet_naming_rule.parameters_rule.style = camel_case_style
# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters dotnet_naming_rule.parameters_rule.severity = warning
dotnet_diagnostic.CA1847.severity = warning
##########################################
# CA1852: Seal internal types # License
dotnet_diagnostic.CA1852.severity = warning ##########################################
# The following applies as to the .editorconfig file ONLY, and is
# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method # included below for reference, per the requirements of the license
dotnet_diagnostic.CA1854.severity = warning # corresponding to this .editorconfig file.
# See: https://github.com/RehanSaeed/EditorConfig
# CA1855: Prefer 'Clear' over 'Fill' #
dotnet_diagnostic.CA1855.severity = warning # MIT License
#
# CA1856: Incorrect usage of ConstantExpected attribute # Copyright (c) 2017-2019 Muhammad Rehan Saeed
dotnet_diagnostic.CA1856.severity = error # Copyright (c) 2019 Henry Gabryjelski
#
# CA1857: A constant is expected for the parameter # Permission is hereby granted, free of charge, to any
dotnet_diagnostic.CA1857.severity = warning # person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# CA1858: Use 'StartsWith' instead of 'IndexOf' # Software without restriction, including without limitation
dotnet_diagnostic.CA1858.severity = warning # the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit
# CA2007: Consider calling ConfigureAwait on the awaited task # persons to whom the Software is furnished to do so, subject
dotnet_diagnostic.CA2007.severity = none # to the following conditions:
#
# CA2008: Do not create tasks without passing a TaskScheduler # The above copyright notice and this permission notice shall be
dotnet_diagnostic.CA2008.severity = warning # included in all copies or substantial portions of the Software.
#
# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
dotnet_diagnostic.CA2009.severity = warning # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# CA2011: Avoid infinite recursion # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
dotnet_diagnostic.CA2011.severity = warning # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# CA2012: Use ValueTask correctly # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
dotnet_diagnostic.CA2012.severity = warning # OTHER DEALINGS IN THE SOFTWARE.
##########################################
# CA2013: Do not use ReferenceEquals with value types
dotnet_diagnostic.CA2013.severity = warning
# CA2014: Do not use stackalloc in loops.
dotnet_diagnostic.CA2014.severity = warning
# CA2016: Forward the 'CancellationToken' parameter to methods that take one
dotnet_diagnostic.CA2016.severity = warning
# CA2200: Rethrow to preserve stack details
dotnet_diagnostic.CA2200.severity = warning
# CA2201: Do not raise reserved exception types
dotnet_diagnostic.CA2201.severity = warning
# CA2208: Instantiate argument exceptions correctly
dotnet_diagnostic.CA2208.severity = warning
# CA2245: Do not assign a property to itself
dotnet_diagnostic.CA2245.severity = warning
# CA2246: Assigning symbol and its member in the same statement
dotnet_diagnostic.CA2246.severity = warning
# CA2249: Use string.Contains instead of string.IndexOf to improve readability.
dotnet_diagnostic.CA2249.severity = warning
# IDE0005: Remove unnecessary usings
dotnet_diagnostic.IDE0005.severity = warning
# IDE0011: Curly braces to surround blocks of code
dotnet_diagnostic.IDE0011.severity = warning
# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)
dotnet_diagnostic.IDE0020.severity = warning
# IDE0029: Use coalesce expression (non-nullable types)
dotnet_diagnostic.IDE0029.severity = warning
# IDE0030: Use coalesce expression (nullable types)
dotnet_diagnostic.IDE0030.severity = warning
# IDE0031: Use null propagation
dotnet_diagnostic.IDE0031.severity = warning
# IDE0035: Remove unreachable code
dotnet_diagnostic.IDE0035.severity = warning
# IDE0036: Order modifiers
csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:suggestion
dotnet_diagnostic.IDE0036.severity = warning
# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)
dotnet_diagnostic.IDE0038.severity = warning
# IDE0043: Format string contains invalid placeholder
dotnet_diagnostic.IDE0043.severity = warning
# IDE0044: Make field readonly
dotnet_diagnostic.IDE0044.severity = warning
# IDE0051: Remove unused private members
dotnet_diagnostic.IDE0051.severity = warning
# IDE0055: All formatting rules
dotnet_diagnostic.IDE0055.severity = suggestion
# IDE0059: Unnecessary assignment to a value
dotnet_diagnostic.IDE0059.severity = warning
# IDE0060: Remove unused parameter
dotnet_code_quality_unused_parameters = non_public
dotnet_diagnostic.IDE0060.severity = warning
# IDE0062: Make local function static
dotnet_diagnostic.IDE0062.severity = warning
# IDE0073: File header
dotnet_diagnostic.IDE0073.severity = warning
# Not a dotnet foundation project
#file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license.
# IDE0161: Convert to file-scoped namespace
dotnet_diagnostic.IDE0161.severity = warning
# IDE0200: Lambda expression can be removed
dotnet_diagnostic.IDE0200.severity = warning
# IDE2000: Disallow multiple blank lines
dotnet_style_allow_multiple_blank_lines_experimental = false
dotnet_diagnostic.IDE2000.severity = warning
[{eng/tools/**.cs,**/{test,testassets,samples,Samples,perf,benchmarkapps,scripts,stress}/**.cs,src/Hosting/Server.IntegrationTesting/**.cs,src/Servers/IIS/IntegrationTesting.IIS/**.cs,src/Shared/Http2cat/**.cs,src/Testing/**.cs}]
# CA1018: Mark attributes with AttributeUsageAttribute
dotnet_diagnostic.CA1018.severity = suggestion
# CA1507: Use nameof to express symbol names
dotnet_diagnostic.CA1507.severity = suggestion
# CA1510: Use ArgumentNullException throw helper
dotnet_diagnostic.CA1510.severity = suggestion
# CA1511: Use ArgumentException throw helper
dotnet_diagnostic.CA1511.severity = suggestion
# CA1512: Use ArgumentOutOfRangeException throw helper
dotnet_diagnostic.CA1512.severity = suggestion
# CA1513: Use ObjectDisposedException throw helper
dotnet_diagnostic.CA1513.severity = suggestion
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = suggestion
# CA1805: Do not initialize unnecessarily
dotnet_diagnostic.CA1805.severity = suggestion
# CA1810: Do not initialize unnecessarily
dotnet_diagnostic.CA1810.severity = suggestion
# CA1822: Make member static
dotnet_diagnostic.CA1822.severity = suggestion
# CA1823: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = suggestion
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
dotnet_diagnostic.CA1826.severity = suggestion
# CA1827: Do not use Count() or LongCount() when Any() can be used
dotnet_diagnostic.CA1827.severity = suggestion
# CA1829: Use Length/Count property instead of Count() when available
dotnet_diagnostic.CA1829.severity = suggestion
# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
dotnet_diagnostic.CA1831.severity = suggestion
# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
dotnet_diagnostic.CA1832.severity = suggestion
# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
dotnet_diagnostic.CA1833.severity = suggestion
# CA1834: Consider using 'StringBuilder.Append(char)' when applicable
dotnet_diagnostic.CA1834.severity = suggestion
# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
dotnet_diagnostic.CA1835.severity = suggestion
# CA1837: Use 'Environment.ProcessId'
dotnet_diagnostic.CA1837.severity = suggestion
# CA1838: Avoid 'StringBuilder' parameters for P/Invokes
dotnet_diagnostic.CA1838.severity = suggestion
# CA1841: Prefer Dictionary.Contains methods
dotnet_diagnostic.CA1841.severity = suggestion
# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'
dotnet_diagnostic.CA1844.severity = suggestion
# CA1845: Use span-based 'string.Concat'
dotnet_diagnostic.CA1845.severity = suggestion
# CA1846: Prefer AsSpan over Substring
dotnet_diagnostic.CA1846.severity = suggestion
# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = suggestion
# CA1852: Seal internal types
dotnet_diagnostic.CA1852.severity = suggestion
# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
dotnet_diagnostic.CA1854.severity = suggestion
# CA1855: Prefer 'Clear' over 'Fill'
dotnet_diagnostic.CA1855.severity = suggestion
# CA1856: Incorrect usage of ConstantExpected attribute
dotnet_diagnostic.CA1856.severity = suggestion
# CA1857: A constant is expected for the parameter
dotnet_diagnostic.CA1857.severity = suggestion
# CA1858: Use 'StartsWith' instead of 'IndexOf'
dotnet_diagnostic.CA1858.severity = suggestion
# CA2007: Consider calling ConfigureAwait on the awaited task
dotnet_diagnostic.CA2007.severity = suggestion
# CA2008: Do not create tasks without passing a TaskScheduler
dotnet_diagnostic.CA2008.severity = suggestion
# CA2012: Use ValueTask correctly
dotnet_diagnostic.CA2012.severity = suggestion
# CA2201: Do not raise reserved exception types
dotnet_diagnostic.CA2201.severity = suggestion
# CA2249: Use string.Contains instead of string.IndexOf to improve readability.
dotnet_diagnostic.CA2249.severity = suggestion
# IDE0005: Remove unnecessary usings
dotnet_diagnostic.IDE0005.severity = suggestion
# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)
dotnet_diagnostic.IDE0020.severity = suggestion
# IDE0029: Use coalesce expression (non-nullable types)
dotnet_diagnostic.IDE0029.severity = suggestion
# IDE0030: Use coalesce expression (nullable types)
dotnet_diagnostic.IDE0030.severity = suggestion
# IDE0031: Use null propagation
dotnet_diagnostic.IDE0031.severity = suggestion
# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)
dotnet_diagnostic.IDE0038.severity = suggestion
# IDE0044: Make field readonly
dotnet_diagnostic.IDE0044.severity = suggestion
# IDE0051: Remove unused private members
dotnet_diagnostic.IDE0051.severity = suggestion
# IDE0059: Unnecessary assignment to a value
dotnet_diagnostic.IDE0059.severity = suggestion
# IDE0060: Remove unused parameters
dotnet_diagnostic.IDE0060.severity = suggestion
# IDE0062: Make local function static
dotnet_diagnostic.IDE0062.severity = suggestion
# IDE0200: Lambda expression can be removed
dotnet_diagnostic.IDE0200.severity = suggestion
# CA2016: Forward the 'CancellationToken' parameter to methods that take one
dotnet_diagnostic.CA2016.severity = suggestion
# Defaults for content in the shared src/ and shared runtime dir
[{**/Shared/runtime/**.{cs,vb},src/Shared/test/Shared.Tests/runtime/**.{cs,vb},**/microsoft.extensions.hostfactoryresolver.sources/**.{cs,vb}}]
# CA1822: Make member static
dotnet_diagnostic.CA1822.severity = silent
# IDE0011: Use braces
dotnet_diagnostic.IDE0011.severity = silent
# IDE0055: Fix formatting
dotnet_diagnostic.IDE0055.severity = silent
# IDE0060: Remove unused parameters
dotnet_diagnostic.IDE0060.severity = silent
# IDE0062: Make local function static
dotnet_diagnostic.IDE0062.severity = silent
# IDE0161: Convert to file-scoped namespace
dotnet_diagnostic.IDE0161.severity = silent
[{**/Shared/**.cs,**/microsoft.extensions.hostfactoryresolver.sources/**.{cs,vb}}]
# IDE0005: Remove unused usings. Ignore for shared src files since imports for those depend on the projects in which they are included.
dotnet_diagnostic.IDE0005.severity = silent

View file

@ -1,127 +0,0 @@
name: Build documentation
run-name: ${{ gitea.actor }} is building the Wiki documentation
on:
push:
branches:
- develop
- master
paths:
- Wiki/**
- Wiki.Dockerfile
env:
# Name of module and id separated by a slash
INSTANCE: Wiki/wiki
# Replace HI with the ID of the instance in capital letters
ARTIFACT: webHelpWIKI2-all.zip
# Writerside docker image version
DOCKER_VERSION: 232.10165.1
ALGOLIA_ARTIFACT: algolia-indexes-wiki.zip
jobs:
preprocess:
runs-on: ubuntu-latest
outputs:
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
steps:
- name: Sanitize branch name
id: sanitize
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
docs:
runs-on: ubuntu-latest
container: registry.jetbrains.team/p/writerside/builder/writerside-builder:${{env.DOCKER_VERSION}}
steps:
- name: Install basic dependencies
run: |
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
echo "::add-path::$HOME/.nvm"
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm install 18
nvm use 18
echo "::add-path::$(dirname $(which npm))"
nvm --version
- name: Check Node.js version
run: |
node -v
npm -v
- name: Checkout repository
uses: https://github.com/actions/checkout@v3
- name: Build docs
run: |
set -e
export DISPLAY=:99
Xvfb :99 &
/opt/builder/bin/idea.sh helpbuilderinspect -source-dir . -product ${{env.INSTANCE}} -output-dir artifacts/ || true
echo "Test existing of ${{ env.ARTIFACT }} artifact"
test -e artifacts/${{ env.ARTIFACT }}
- name: rename artifact
run: |
mv artifacts/${{ env.ARTIFACT }} artifacts/wiki.zip
- name: Upload documentation
uses: actions/upload-artifact@v3
with:
name: wiki.zip
path: artifacts/wiki.zip
retention-days: 14
- name: Upload algolia-indexes
uses: actions/upload-artifact@v4
with:
name: algolia-indexes.zip
path: artifacts/${{ env.ALGOLIA_ARTIFACT }}
retention-days: 14
build-docs-container:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
needs: [docs, preprocess]
steps:
- name: Checkout repository
uses: https://github.com/actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ github.server_url }}
username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Retrieve docs artifact
uses: actions/download-artifact@v4
with:
name: wiki.zip
path: ${{ github.workspace }}
- name: Unzip wiki.zip into .public
run: |
mkdir .public
unzip -jo -qq ./wiki.zip/wiki.zip -d .public
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: Wiki.Dockerfile
push: true
tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}-wiki
platforms: linux/amd64,linux/arm64
- name: Build and push to latest
if: github.ref_name == 'master'
uses: docker/build-push-action@v5
with:
context: .
file: Wiki.Dockerfile
push: true
tags: forge.rainote.dev/${{ github.repository }}:latest-wiki
platforms: linux/amd64, linux/arm64
deploy-wiki:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
needs: [build-docs-container, docs, preprocess]
steps:
- name: Deploy Image to CapRrover
run: |
docker run caprover/cli-caprover:2.2.3 caprover deploy --caproverUrl ${{ secrets.CAPROVER_SERVER }} --appToken ${{ secrets.WIKI_APP_TOKEN }} --imageName forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}-wiki -a ${{ secrets.WIKI_APP_NAME }}

View file

@ -1,206 +1,13 @@
name: Build, Package and Push Images name: Test if Server can be built
run-name: ${{ gitea.actor }} is building the Server application run-name: ${{ gitea.actor }} is building the Server application
on: on: [ push ]
push:
branches:
- develop
- master
paths-ignore:
- Wiki/**
- Benchmarks/**
- .run/**
jobs: jobs:
preprocess: build-server:
runs-on: ubuntu-latest
outputs:
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
steps: steps:
- name: Sanitize branch name - uses: actions/checkout@v3
id: sanitize
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup dotnet - name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3 uses: https://github.com/actions/setup-dotnet@v3
with: with:
global-json-file: global.json global-json-file: global.json
- name: Install dependencies - run: dotnet build Server
run: dotnet restore
- name: Build
run: |
dotnet build Continuity.AuthServer -c Release
sonarqube:
needs: build
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
if: github.ref_name == 'master'
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Install dependencies
run: |
dotnet restore
echo "::add-path::$HOME/.dotnet/tools"
- name: Setup Sonarqube Dependencies
run: |
apt-get update
apt-get install --yes openjdk-18-jre
dotnet tool install --global dotnet-sonarscanner
dotnet tool install --global dotnet-coverage
- name: Sonarqube Begin
run: |
dotnet sonarscanner begin /key:"${{ secrets.SONAR_PROJECT_KEY }}" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="${{ secrets.SONAR_HOST_URL }}"
- name: Sonarqube Scan
run: |
dotnet build Continuity.AuthServer -c Release
# dotnet test --collect "Code Coverage" --logger trx --results-directory "TestsResults"
# dotnet-coverage collect 'dotnet test' -f xml -o 'coverage.xml'
- name: Sonarqube End
run: |
dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
sbom-scan:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Install dependencies
run: |
dotnet restore
echo "::add-path::$HOME/.dotnet/tools"
- name: Setup Dependency Track Dependencies
run: |
dotnet tool install --global CycloneDX
- name: Generate SBOM
run: |
dotnet CycloneDX Continuity.AuthServer/Continuity.AuthServer.csproj -o . -dgl
- name: Upload SBOM
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
with:
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}
autoCreate: true
# set projectversion to be the branch name
projectVersion: ${{ github.ref_name }}
bomFilename: ${{ github.workspace }}/bom.xml
container-build:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
needs: [build, preprocess]
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
# Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ github.server_url }}
username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: Continuity.AuthServer/Dockerfile
push: true
tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
platforms: linux/amd64,linux/arm64
- name: Build and push to latest
if: github.ref_name == 'master'
uses: docker/build-push-action@v5
with:
context: .
file: Continuity.AuthServer/Dockerfile
push: true
tags: forge.rainote.dev/${{ github.repository }}:latest
platforms: linux/amd64, linux/arm64
container-sbom-scan:
needs: [container-build, preprocess]
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Install dependencies
run: |
dotnet restore
echo "::add-path::$HOME/.dotnet/tools"
- name: Setup Dependency Track Dependencies
run: |
mkdir ~/.docker
curl -sSfL https://raw.githubusercontent.com/docker/sbom-cli-plugin/main/install.sh | sh -s --
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ github.server_url }}
username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Generate SBOM
run: |
echo forge.rainote.dev/${{ github.repository }}
echo forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
docker pull forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
docker sbom -D forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }} --format cyclonedx-json --output container-bom.json
- name: Upload SBOM
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
with:
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}-container
autoCreate: true
# set projectversion to be the branch name
projectVersion: ${{ github.ref_name }}
bomFilename: ${{ github.workspace }}/container-bom.json
generate-licences:
needs: [build, preprocess]
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
dotnet-version: |
7.0
8.0
- name: Install dependencies
run: |
dotnet restore
echo "::add-path::$HOME/.dotnet/tools"
- name: Install nuget-license
run: dotnet tool install --global dotnet-project-licenses
- name: Export licenses
run: dotnet-project-licenses -i . -u --projects-filter projects_ignore_licenses.json -m -j -e -f licenses
- name: Upload licenses
uses: actions/upload-artifact@v3
with:
name: licenses
path: licenses
retention-days: 31

View file

@ -1,170 +0,0 @@
name: PR Workflow
run-name: ${{ gitea.actor }} PR related workflow
on:
pull_request:
paths-ignore:
- Wiki/**
- Benchmarks/**
- .run/**
jobs:
preprocess:
runs-on: ubuntu-latest
outputs:
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
steps:
- name: Sanitize branch name
id: sanitize
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Install dependencies
run: dotnet restore
- name: Build
run: |
dotnet build Continuity.AuthServer -c Release
sbom-scan:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Install dependencies
run: |
dotnet restore
echo "::add-path::$HOME/.dotnet/tools"
- name: Setup Dependency Track Dependencies
run: |
dotnet tool install --global CycloneDX
- name: Generate SBOM
run: |
dotnet CycloneDX Continuity.AuthServer/Continuity.AuthServer.csproj -o . -dgl
- name: Upload SBOM
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
with:
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}
autoCreate: true
# set projectversion to be the branch name
projectVersion: ${{ github.ref_name }}
bomFilename: ${{ github.workspace }}/bom.xml
container-build:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
needs: [ build, preprocess ]
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
# Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ github.server_url }}
username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: Continuity.AuthServer/Dockerfile
push: true
tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
platforms: linux/amd64,linux/arm64
- name: Build and push to latest
if: github.ref_name == 'master'
uses: docker/build-push-action@v5
with:
context: .
file: Continuity.AuthServer/Dockerfile
push: true
tags: forge.rainote.dev/${{ github.repository }}:latest
platforms: linux/amd64, linux/arm64
container-sbom-scan:
needs: [ container-build, preprocess ]
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Install dependencies
run: |
dotnet restore
echo "::add-path::$HOME/.dotnet/tools"
- name: Setup Dependency Track Dependencies
run: |
mkdir ~/.docker
curl -sSfL https://raw.githubusercontent.com/docker/sbom-cli-plugin/main/install.sh | sh -s --
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ github.server_url }}
username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Generate SBOM
run: |
echo forge.rainote.dev/${{ github.repository }}
echo forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
docker pull forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
docker sbom -D forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }} --format cyclonedx-json --output container-bom.json
- name: Upload SBOM
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
with:
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}-container
autoCreate: true
# set projectversion to be the branch name
projectVersion: ${{ github.ref_name }}
bomFilename: ${{ github.workspace }}/container-bom.json
generate-licences:
needs: [ build, preprocess ]
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3
with:
dotnet-version: |
7.0
8.0
- name: Install dependencies
run: |
dotnet restore
echo "::add-path::$HOME/.dotnet/tools"
- name: Install nuget-license
run: dotnet tool install --global dotnet-project-licenses
- name: Export licenses
run: dotnet-project-licenses -i . -u --projects-filter projects_ignore_licenses.json -m -j -e -f licenses
- name: Upload licenses
uses: actions/upload-artifact@v3
with:
name: licenses
path: licenses
retention-days: 31

6
.gitignore vendored
View file

@ -3,8 +3,6 @@
## ##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
licenses
# User-specific files # User-specific files
*.rsuser *.rsuser
*.suo *.suo
@ -482,7 +480,3 @@ $RECYCLE.BIN/
.idea .idea
.vscode .vscode
.nuke
wk-data

118
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,118 @@
image: mcr.microsoft.com/dotnet/sdk:latest
# ### Define variables
#
variables:
# 1) Name of directory where restore and build objects are stored.
OBJECTS_DIRECTORY: 'obj'
# 2) Name of directory used for keeping restored dependencies.
NUGET_PACKAGES_DIRECTORY: '.nuget'
# 3) A relative path to the source code from project repository root.
# NOTE: Please edit this path so it matches the structure of your project!
SOURCE_CODE_PATH: '*/*/'
# ### Define global cache rule
#
# Before building the project, all dependencies (e.g. third-party NuGet packages)
# must be restored. Jobs on GitLab.com's Shared Runners are executed on autoscaled machines.
#
# Each machine is used only once (for security reasons) and after that is removed.
# This means that, before every job, a dependency restore must be performed
# because restored dependencies are removed along with machines. Fortunately,
# GitLab provides cache mechanism with the aim of keeping restored dependencies
# for other jobs.
#
# This example shows how to configure cache to pass over restored
# dependencies for re-use.
#
# With global cache rule, cached dependencies will be downloaded before every job
# and then unpacked to the paths as specified below.
cache:
# Per-stage and per-branch caching.
key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
paths:
# Specify three paths that should be cached:
#
# 1) Main JSON file holding information about package dependency tree, packages versions,
# frameworks etc. It also holds information where to the dependencies were restored.
- '$SOURCE_CODE_PATH$OBJECTS_DIRECTORY/project.assets.json'
# 2) Other NuGet and MSBuild related files. Also needed.
- '$SOURCE_CODE_PATH$OBJECTS_DIRECTORY/*.csproj.nuget.*'
# 3) Path to the directory where restored dependencies are kept.
- '$NUGET_PACKAGES_DIRECTORY'
#
# 'pull-push' policy means that latest cache will be downloaded (if it exists)
# before executing the job, and a newer version will be uploaded afterwards.
# Such a setting saves time when there are no changes in referenced third-party
# packages.
#
# For example, if you run a pipeline with changes in your code,
# but with no changes within third-party packages which your project is using,
# then project restore will happen quickly as all required dependencies
# will already be there — unzipped from cache.
# 'pull-push' policy is the default cache policy, you do not have to specify it explicitly.
policy: pull-push
# ### Restore project dependencies
#
# NuGet packages by default are restored to '.nuget/packages' directory
# in the user's home directory. That directory is out of scope of GitLab caching.
#
# To get around this, a custom path can be specified using the '--packages <PATH>' option
# for 'dotnet restore' command. In this example, a temporary directory is created
# in the root of project repository, so its content can be cached.
#
# Learn more about GitLab cache: https://docs.gitlab.com/ee/ci/caching/index.html
before_script:
- 'dotnet restore --packages $NUGET_PACKAGES_DIRECTORY'
build:
stage: build
# ### Build all projects discovered from solution file.
#
# Note: this will fail if you have any projects in your solution that are not
# .NET Core-based projects (e.g. WCF service), which is based on .NET Framework,
# not .NET Core. In this scenario, you will need to build every .NET Core-based
# project by explicitly specifying a relative path to the directory
# where it is located (e.g. 'dotnet build ./src/ConsoleApp').
# Only one project path can be passed as a parameter to 'dotnet build' command.
script:
- 'dotnet build --no-restore'
tests:
stage: test
# ### Run the tests
#
# You can either run tests for all test projects that are defined in your solution
# with 'dotnet test' or run tests only for specific project by specifying
# a relative path to the directory where it is located (e.g. 'dotnet test ./test/UnitTests').
#
# You may want to define separate testing jobs for different types of testing
# (e.g. integration tests, unit tests etc).
script:
- 'dotnet test --no-restore'
sonarqube-check:
image: mcr.microsoft.com/dotnet/sdk:latest
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- "apt-get update"
- "apt-get install --yes openjdk-11-jre"
- "dotnet tool install --global dotnet-sonarscanner"
- "dotnet tool install --global dotnet-coverage"
- "export PATH=\"$PATH:$HOME/.dotnet/tools\""
- "dotnet sonarscanner begin /k:\"wonderking_continuity_AYeecUUTs-PH__JrTRky\" /d:sonar.token=\"$SONAR_TOKEN\" /d:\"sonar.host.url=$SONAR_HOST_URL\" "
- "dotnet build"
- "dotnet test --collect \"Code Coverage\" --logger trx --results-directory \"TestsResults\""
# - "dotnet-coverage collect 'dotnet test' -f xml -o 'coverage.xml'"
- "dotnet sonarscanner end /d:sonar.login=\"$SONAR_TOKEN\""
allow_failure: true
only:
- master

View file

@ -1,19 +0,0 @@
repos:
- repo: local
hooks:
#Use dotnet format already installed on your machine
- id: dotnet-format
name: dotnet-format
language: system
entry: dotnet format --include
types_or: [c#, vb]
- repo: https://github.com/Mateusz-Grzelinski/actionlint-py
rev: v1.6.26.11
hooks:
- id: actionlint
additional_dependencies: [pyflakes>=3.0.1, shellcheck-py>=0.9.0.5]
- repo: https://github.com/hadolint/hadolint
rev: v2.12.0
hooks:
- id: hadolint-docker
args: [--ignore, SC2086]

View file

@ -1,16 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Server/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="continuity" />
<option name="buildCliOptions" value="--platform linux/amd64" />
<option name="buildKitEnabled" value="true" />
<option name="buildOnly" value="true" />
<option name="contextFolderPath" value="." />
<option name="sourceFilePath" value="Server/Dockerfile" />
</settings>
</deployment>
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
<method v="2" />
</configuration>
</component>

View file

@ -1,6 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="build images" type="PowerShellRunType" factoryName="PowerShell" scriptUrl="C:\Users\Timot\Projects\Continuity\build-image.ps1" workingDirectory="C:\Users\Timot\Projects\Continuity" executablePath="C:\Users\Timot\scoop\apps\pwsh\current\pwsh.exe">
<envs />
<method v="2" />
</configuration>
</component>

View file

@ -1,19 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="docker-compose.yml: Compose Deployment" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="buildKitEnabledForCompose" value="true" />
<option name="envFilePath" value="" />
<option name="sourceFilePath" value="docker-compose.yml" />
<option name="upDetach" value="false" />
<option name="upRemoveOrphans" value="true" />
</settings>
</deployment>
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
<method v="2">
<option name="Build" default="false" projectName="Wonderking" projectPath="$PROJECT_DIR$/Wonderking/Wonderking.csproj" />
<option name="Build" default="false" projectName="Server" projectPath="$PROJECT_DIR$/Server/Server.csproj" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="build images" run_configuration_type="PowerShellRunType" />
</method>
</configuration>
</component>

View file

@ -1,128 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
using Isopoh.Cryptography.Argon2;
using Konscious.Security.Cryptography;
using Argon2 = Isopoh.Cryptography.Argon2.Argon2;
namespace Benchmarks;
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[Config(typeof(GenericConfig))]
public class Argon2Benchmarks
{
[Params(2, 4)] public int _iterations;
[Params(16, 32)] public int _memory;
[Params(1, 2)] public int _parallelism;
private byte[] _salt = null!;
private byte[] _additionalData = null!;
[Params(16)] public int _length;
private byte[] _password = null!;
[GlobalSetup]
public void Setup()
{
_salt = RandomNumberGenerator.GetBytes(16);
_additionalData = RandomNumberGenerator.GetBytes(16);
_password = RandomNumberGenerator.GetBytes(16);
}
[Benchmark]
public byte[] Argon2i()
{
return new Argon2i(_password)
{
Iterations = _iterations,
MemorySize = 1024 * _memory,
DegreeOfParallelism = _parallelism,
AssociatedData = _additionalData,
Salt = _salt,
}.GetBytes(_length);
}
[Benchmark]
public byte[] Argon2d()
{
return new Argon2d(_password)
{
Iterations = _iterations,
MemorySize = 1024 * _memory,
DegreeOfParallelism = _parallelism,
AssociatedData = _additionalData,
Salt = _salt,
}.GetBytes(_length);
}
[Benchmark]
public byte[] Argon2id()
{
return new Argon2id(_password)
{
Iterations = _iterations,
MemorySize = 1024 * _memory,
DegreeOfParallelism = _parallelism,
AssociatedData = _additionalData,
Salt = _salt,
}.GetBytes(_length);
}
[Benchmark]
public byte[] IsopohArgon2DD()
{
var config = new Argon2Config
{
Type = Argon2Type.DataDependentAddressing,
Version = Argon2Version.Nineteen,
MemoryCost = 1024 * _memory,
TimeCost = _iterations,
Lanes = _parallelism,
HashLength = _length,
Salt = _salt,
AssociatedData = _additionalData,
Password = _password,
};
var argon2 = new Argon2(config);
return argon2.Hash().Buffer;
}
[Benchmark]
public byte[] IsopohArgon2DI()
{
var config = new Argon2Config
{
Type = Argon2Type.DataIndependentAddressing,
Version = Argon2Version.Nineteen,
MemoryCost = 1024 * _memory,
TimeCost = _iterations,
Lanes = _parallelism,
HashLength = _length,
Salt = _salt,
AssociatedData = _additionalData,
Password = _password,
};
var argon2 = new Argon2(config);
return argon2.Hash().Buffer;
}
[Benchmark]
public byte[] IsopohArgon2Hybrid()
{
var config = new Argon2Config
{
Type = Argon2Type.HybridAddressing,
Version = Argon2Version.Nineteen,
MemoryCost = 1024 * _memory,
TimeCost = _iterations,
Lanes = _parallelism,
HashLength = _length,
Salt = _salt,
AssociatedData = _additionalData,
Password = _password,
};
var argon2 = new Argon2(config);
return argon2.Hash().Buffer;
}
}

View file

@ -4,27 +4,12 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>12</LangVersion> <LangVersion>default</LangVersion>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks> <TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AsyncFixer" Version="1.6.0"> <PackageReference Include="BenchmarkDotNet" Version="0.13.7"/>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
<PackageReference Include="DotNext.Unsafe" Version="0.14.0" />
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.146">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.9.28">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,70 +1,44 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. namespace Benchmarks;
using System.Buffers.Binary;
using System.Security.Cryptography; using System.Security.Cryptography;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Order; using BenchmarkDotNet.Order;
namespace Benchmarks; [SimpleJob(RuntimeMoniker.NativeAot70)]
[SimpleJob(RuntimeMoniker.Net70)]
[SimpleJob(RuntimeMoniker.Net60)]
[Orderer(SummaryOrderPolicy.FastestToSlowest)] [Orderer(SummaryOrderPolicy.FastestToSlowest)]
[Config(typeof(GenericConfig))] [RankColumn]
[MemoryDiagnoser]
[ExceptionDiagnoser]
[ThreadingDiagnoser]
public class BinaryConversionBenchmarks public class BinaryConversionBenchmarks
{ {
private byte[] _data = null!; private byte[] data;
private int _offset; private int offset;
private int _writeBuffer;
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
_data = RandomNumberGenerator.GetBytes(4000); this.data = RandomNumberGenerator.GetBytes(4000);
_offset = RandomNumberGenerator.GetInt32(0, 3500); this.offset = RandomNumberGenerator.GetInt32(0, 3500);
_writeBuffer = RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);
} }
[Benchmark] [Benchmark]
public short BitConverterParseTest() public short BitConverterTest() => BitConverter.ToInt16(this.data, this.offset);
{
return BitConverter.ToInt16(_data, _offset);
}
[Benchmark] [Benchmark]
public short BinaryReader() public short BinaryReader()
{ {
using var ms = new MemoryStream(_data); using var ms = new MemoryStream(this.data);
using var reader = new BinaryReader(ms); using var reader = new BinaryReader(ms);
reader.BaseStream.Position = _offset; reader.BaseStream.Position = this.offset;
return reader.ReadInt16(); return reader.ReadInt16();
} }
[Benchmark] [Benchmark]
public short BinaryPrimitivesRead() public short BinaryPrimitives() =>
{ System.Buffers.Binary.BinaryPrimitives.ReadInt16LittleEndian(
return BinaryPrimitives.ReadInt16LittleEndian( new ArraySegment<byte>(this.data, this.offset, sizeof(short)));
new ArraySegment<byte>(_data, _offset, sizeof(short)));
}
[Benchmark]
public void BinaryPrimitivesWrite()
{
BinaryPrimitives.WriteInt32LittleEndian(_data.AsSpan(_offset, 4),
_writeBuffer);
}
[Benchmark]
public void BitConverterCopy()
{
BitConverter.GetBytes(_writeBuffer).CopyTo(_data, _offset);
}
[Benchmark]
public void BitConverterAssignment()
{
var bytes = BitConverter.GetBytes(_writeBuffer);
_data[_offset] = bytes[0];
_data[_offset + 1] = bytes[1];
_data[_offset + 2] = bytes[2];
_data[_offset + 3] = bytes[3];
}
} }

View file

@ -1,86 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Collections.Concurrent;
using System.Collections.Immutable;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
namespace Benchmarks;
[Config(typeof(GenericConfig))]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
public class DataCacheBenchmark
{
private ConcurrentDictionary<int, int> _concurrentDictionary;
private Dictionary<int, int> _dictionary;
private HashSet<int> _hashSet;
private ImmutableHashSet<int> _immutableHashSet;
[Params(1000, 100000, 1000000)] public int N;
[GlobalSetup]
public void Setup()
{
_hashSet = new HashSet<int>();
_dictionary = new Dictionary<int, int>();
_concurrentDictionary = new ConcurrentDictionary<int, int>();
_immutableHashSet = ImmutableHashSet<int>.Empty;
_hashSet.Clear();
_dictionary.Clear();
_concurrentDictionary.Clear();
_immutableHashSet = _immutableHashSet.Clear();
_hashSet.EnsureCapacity(N);
_dictionary.EnsureCapacity(N);
for (var i = 0; i < N; i++)
{
_immutableHashSet = _immutableHashSet.Add(i);
_hashSet.Add(i);
_dictionary.Add(i, i);
_concurrentDictionary.TryAdd(i, i);
}
}
[Benchmark]
public void HashSetAdd()
{
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _hashSet.Add(i));
}
[Benchmark]
public void DictionaryAdd()
{
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _dictionary.Add(N + i, i));
}
[Benchmark]
public void ConcurrentDictionaryAddOrUpdate()
{
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i =>
_concurrentDictionary.AddOrUpdate(N + i, i, (key, oldValue) => oldValue + i));
}
[Benchmark]
public void ImmutableHashSetLookup()
{
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _immutableHashSet.Contains(i));
}
[Benchmark]
public void HashSetLookup()
{
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _hashSet.Contains(i));
}
[Benchmark]
public void DictionaryLookup()
{
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _dictionary.ContainsKey(i));
}
[Benchmark]
public void ConcurrentDictionaryLookup()
{
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _concurrentDictionary.ContainsKey(i));
}
}

View file

@ -1,33 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Jobs;
namespace Benchmarks;
public class GenericConfig : ManualConfig
{
public GenericConfig()
{
AddJob(Job.Default
.WithRuntime(CoreRuntime.Core80))
.AddDiagnoser(ThreadingDiagnoser.Default, MemoryDiagnoser.Default,
EventPipeProfiler.Default)
.AddAnalyser(MinIterationTimeAnalyser.Default, OutliersAnalyser.Default,
RuntimeErrorAnalyser.Default, EnvironmentAnalyser.Default)
.AddColumn(RankColumn.Arabic).AddExporter(CsvExporter.Default, MarkdownExporter.Default);
AddJob(Job.Default
.WithRuntime(CoreRuntime.Core70))
.AddDiagnoser(ThreadingDiagnoser.Default, MemoryDiagnoser.Default,
EventPipeProfiler.Default)
.AddAnalyser(MinIterationTimeAnalyser.Default, OutliersAnalyser.Default,
RuntimeErrorAnalyser.Default, EnvironmentAnalyser.Default)
.AddColumn(RankColumn.Arabic).AddExporter(CsvExporter.Default, MarkdownExporter.Default);
}
}

View file

@ -1,6 +1,9 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. namespace Benchmarks;
using System.Reflection; using System.Reflection;
using BenchmarkDotNet.Running; using BenchmarkDotNet.Running;
BenchmarkRunner.Run(Assembly.GetExecutingAssembly()); internal class Program
{
public static void Main(string[] args) => BenchmarkRunner.Run(Assembly.GetExecutingAssembly());
}

File diff suppressed because it is too large Load diff

View file

@ -1,115 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Net.Sockets;
using System.Reflection;
using Continuity.AuthServer.Packets;
using MassTransit.Mediator;
using Microsoft.Extensions.Logging;
using NetCoreServer;
using Wonderking.Packets;
namespace Continuity.AuthServer;
public class AuthSession : TcpSession
{
private readonly ILogger<AuthSession> _logger;
private readonly IMediator _mediator;
public AuthSession(TcpServer
server, IMediator mediator, ILogger<AuthSession> logger) : base(server)
{
_mediator = mediator;
_logger = logger;
}
public Guid AccountId { get; set; }
public override long Send(byte[] buffer)
{
_logger.LogInformation("Data being sent is: {Data}", BitConverter.ToString(buffer));
return base.Send(buffer);
}
public Task SendAsync(IPacket packet)
{
var type = packet.GetType();
_logger.LogInformation("Packet of type {Type} is being serialized", type.Name);
var packetIdAttribute = type.GetCustomAttribute<PacketIdAttribute>();
if (packetIdAttribute == null)
{
return Task.CompletedTask;
}
var opcode = packetIdAttribute.Code;
Span<byte> packetData = packet.Serialize();
var length = (ushort)(packetData.Length + 8);
Span<byte> buffer = stackalloc byte[length];
buffer.Clear();
packetData.CopyTo(buffer[8..length]);
var bytesOfLength = BitConverter.GetBytes(length);
var bytesOfOpcode = BitConverter.GetBytes((ushort)opcode);
for (var i = 0; i < bytesOfLength.Length || i < 2; i++)
{
buffer[i] = bytesOfLength[i];
}
for (var i = 0; i < bytesOfOpcode.Length || i < 2; i++)
{
buffer[2 + i] = bytesOfOpcode[i];
}
_logger.LogInformation("Packet data being parsed is: {Data}", BitConverter.ToString(packetData.ToArray()));
_logger.LogInformation("Packet being parsed is: {Data}", BitConverter.ToString(buffer.ToArray()));
SendAsync(buffer);
return Task.CompletedTask;
}
protected override void OnReceived(byte[] buffer, long offset, long size)
{
_logger.LogDebug("Length: {Size} & offset: {Offset}", size, offset);
Span<byte> decryptedBuffer = stackalloc byte[(int)size];
// xor every value after the first 8 bytes
var dataBuffer = Decrypt(buffer.AsSpan(8, (int)size - 8));
_logger.LogDebug("Length {Length}", BitConverter.ToUInt16(buffer, 0));
var opCode = BitConverter.ToUInt16(buffer.ToArray(), 2);
_logger.LogDebug("Packet Op Code: {OpCode}", opCode);
_logger.LogDebug("Some Value: {RandomValue}", buffer[4]);
var clientAliveTime = BitConverter.ToUInt16(buffer.ToArray(), 5);
_logger.LogDebug("Client Alive time: {ClientAliveTime}", clientAliveTime);
_logger.LogDebug("Might be a flag: {Flag}", buffer[7]);
_logger.LogDebug("Full buffer: {Buffer}", BitConverter.ToString(dataBuffer.ToArray()));
var rawPacket = new RawPacket((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[7],
buffer[4], Id, this);
_ = _mediator.Send(rawPacket);
_logger.LogInformation("Connection from: {@RemoteEndpoint}", Socket.RemoteEndPoint?.ToString());
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
}
private static Span<byte> Decrypt(Span<byte> buffer)
{
for (var i = 0; i < buffer.Length; ++i)
{
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
}
return buffer;
}
protected override void OnError(SocketError error)
{
_logger.LogWarning("An error has occured: {Error}", error);
}
}

View file

@ -1,75 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Security.Cryptography;
using System.Text;
using MassTransit.Mediator;
using Microsoft.Extensions.Logging;
using NetCoreServer;
namespace Continuity.AuthServer;
public class ChannelSession : TcpSession
{
private static readonly byte[] _key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 }
.Reverse().ToArray();
private static readonly byte[] _iv = new byte[]
{
0xfe, 220, 0xba, 0x98, 0x76, 0x54, 50, 0x10, 15, 30, 0x2d, 60, 0x4b, 90, 0x69, 120
}.Reverse().ToArray();
private readonly ICryptoTransform _decryptor;
private readonly ICryptoTransform _encryptor;
private readonly ILogger<ChannelSession> _logger;
private readonly IMediator _mediator;
public ChannelSession(TcpServer server, IMediator mediator, ILogger<ChannelSession> logger) : base(server)
{
_mediator = mediator;
_logger = logger;
var aes = Aes.Create();
aes.Key = _key;
aes.IV = _iv;
aes.Padding = PaddingMode.None;
#pragma warning disable SEC0026
aes.Mode = CipherMode.ECB;
#pragma warning restore SEC0026
_decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
_encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
}
protected override void OnReceived(byte[] buffer, long offset, long size)
{
try
{
using (var ms = new MemoryStream(Decrypt(buffer)))
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Read))
{
var amountOfReadBytes = cs.Read(buffer);
if (amountOfReadBytes != buffer.Length)
{
_logger.LogError("Amount of read bytes is not equal to buffer length");
}
}
base.OnReceived(buffer, offset, size);
}
catch (CryptographicException ex)
{
_logger.LogError("An error has occured while decrypting: {ErrorMessage}", ex.Message);
_logger.LogError("Default buffer message: {Message}", Encoding.ASCII.GetString(buffer));
}
}
private static byte[] Decrypt(byte[] buffer)
{
for (var i = 0; i < buffer.Length; ++i)
{
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
}
return buffer;
}
}

View file

@ -1,23 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.Packets;
using Continuity.AuthServer.Services;
using MassTransit;
namespace Continuity.AuthServer.Consumers;
public class PacketConsumer : IConsumer<RawPacket>
{
private readonly PacketDistributorService _distributorService;
public PacketConsumer(PacketDistributorService distributorService)
{
_distributorService = distributorService;
}
public Task Consume(ConsumeContext<RawPacket> context)
{
_distributorService.AddPacket(context.Message);
return Task.CompletedTask;
}
}

View file

@ -1,121 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>warnings</Nullable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<LangVersion>default</LangVersion>
<ServerGarbageCollection>true</ServerGarbageCollection>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<Features>strict</Features>
<Authors>Timothy (RaiNote) Schenk</Authors>
<Copyright>Timothy (RaiNote) Schenk</Copyright>
<PackageProjectUrl>https://forge.rainote.dev/wonderking/continuity</PackageProjectUrl>
<RepositoryUrl>https://forge.rainote.dev/wonderking/continuity</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
<WarningLevel>7</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
<WarningLevel>7</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Content Include="..\.dockerignore">
<Link>.dockerignore</Link>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="DotNext" Version="5.13.0" />
<PackageReference Include="DotNext.IO" Version="5.13.0" />
<PackageReference Include="DotNext.Metaprogramming" Version="5.13.0" />
<PackageReference Include="DotNext.Threading" Version="5.13.0" />
<PackageReference Include="DotNext.Unsafe" Version="5.13.0" />
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0"/>
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0"/>
<PackageReference Include="MassTransit" Version="8.1.3" />
<PackageReference Include="MassTransit.Analyzers" Version="8.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.146">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0"/>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.9.28">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NetCoreServer" Version="8.0.7" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
<PackageReference Include="Npgsql.OpenTelemetry" Version="8.0.2" />
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.15.6169">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="OpenTelemetry" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.10"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="1.0.0-alpha.6" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.PersistentStorage.FileSystem" Version="1.0.0"/>
<PackageReference Include="OpenTelemetry.ResourceDetectors.Container" Version="1.0.0-beta.6"/>
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0"/>
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
</ItemGroup>
<ItemGroup>
<Content Include="settings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wonderking\Wonderking.csproj"/>
</ItemGroup>
</Project>

View file

@ -1,34 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Continuity.AuthServer.DB.Documents;
[Index(nameof(Username), IsUnique = true)]
[Index(nameof(Id), IsUnique = true)]
public class Account
{
public Account(string username, byte[] password, string email, byte permissionLevel, byte[] salt)
{
Username = username;
Password = password;
Email = email;
PermissionLevel = permissionLevel;
Salt = salt;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[MaxLength(20)] public string Username { get; set; }
[Column(TypeName = "bytea")] public byte[] Password { get; set; }
[EmailAddress] public string Email { get; set; }
public byte PermissionLevel { get; set; }
[Column(TypeName = "bytea")] public byte[] Salt { get; set; }
public virtual ICollection<Character> Characters { get; set; }
}

View file

@ -1,45 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Wonderking.Game.Data.Character;
using Wonderking.Packets.Outgoing.Data;
namespace Continuity.AuthServer.DB.Documents;
[Index(nameof(Name), IsUnique = true)]
[Index(nameof(Id), IsUnique = true)]
public class Character
{
[DeleteBehavior(DeleteBehavior.Cascade)]
[Required]
public virtual Account Account { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public ushort MapId { get; set; }
[MaxLength(20)] public string Name { get; set; }
public short LastXCoordinate { get; set; }
public short LastYCoordinate { get; set; }
public PvPLevel PvPLevel { get; set; }
public Gender Gender { get; set; }
public long Experience { get; set; }
public byte Level { get; set; }
[DeleteBehavior(DeleteBehavior.Cascade)]
public virtual ICollection<InventoryItem> InventoryItems { get; set; }
public BaseStats BaseStats { get; set; }
public JobData JobData { get; set; }
public int Health { get; set; }
public int Mana { get; set; }
[DeleteBehavior(DeleteBehavior.Cascade)]
public virtual GuildMember GuildMember { get; set; }
}

View file

@ -1,22 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Continuity.AuthServer.DB.Documents;
[Index(nameof(Name), IsUnique = true)]
[Index(nameof(Id), IsUnique = true)]
public class Guild
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[MaxLength(16)] public string Name { get; set; }
public string Notice { get; set; }
[DeleteBehavior(DeleteBehavior.Cascade)]
public virtual ICollection<GuildMember> GuildMembers { get; set; }
}

View file

@ -1,31 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Continuity.AuthServer.DB.Documents;
[Index(nameof(Id), IsUnique = true)]
public class GuildMember
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual Guid CharacterId { get; set; }
[DeleteBehavior(DeleteBehavior.Restrict)]
[ForeignKey(nameof(CharacterId))]
[Required]
public virtual Character Character { get; set; }
public virtual Guid GuildId { get; set; }
[DeleteBehavior(DeleteBehavior.Restrict)]
[ForeignKey(nameof(GuildId))]
[Required]
public virtual Guild Guild { get; set; }
public GuildRank Rank { get; set; }
}

View file

@ -1,13 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
namespace Continuity.AuthServer.DB.Documents;
public enum GuildRank : byte
{
Initiate = 0,
Member = 1,
Veteran = 2,
Elite = 3,
Officer = 4,
Master = 5
}

View file

@ -1,31 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Continuity.AuthServer.DB.Documents;
public class InventoryItem
{
[DeleteBehavior(DeleteBehavior.Restrict)]
[Required]
public virtual Character Character { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public ushort ItemId { get; set; }
public ushort Count { get; set; }
public byte Slot { get; set; }
public InventoryTab InventoryTab { get; set; }
public byte Level { get; set; }
public byte Rarity { get; set; }
public byte AddOption { get; set; }
public byte AddOption2 { get; set; }
public byte AddOption3 { get; set; }
public short Option { get; set; }
public short Option2 { get; set; }
public short Option3 { get; set; }
}

View file

@ -1,14 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
namespace Continuity.AuthServer.DB.Documents;
public enum InventoryTab : byte
{
WornEquipment = 0,
WornCashEquipment = 1,
Equipment = 2,
Etc = 3,
Cash = 4,
Warehouse = 5,
GiftBox = 6
}

View file

@ -1,28 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
#nullable disable
namespace Server.DB.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) => migrationBuilder.CreateTable(
name: "Accounts",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Username = table.Column<string>(type: "varchar(20)", nullable: false),
Password = table.Column<byte[]>(type: "bytea", nullable: false),
Email = table.Column<string>(type: "text", nullable: false),
PermissionLevel = table.Column<byte>(type: "smallint", nullable: false),
Salt = table.Column<byte[]>(type: "bytea", nullable: false)
},
constraints: table => table.PrimaryKey("PK_Accounts", x => x.Id));
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder) => migrationBuilder.DropTable(
name: "Accounts");
}

View file

@ -1,116 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20230817230423_CharacterDataDraft")]
partial class CharacterDataDraft
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.Property<byte>("ServerId")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,125 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
#nullable disable
namespace Server.DB.Migrations;
using Microsoft.EntityFrameworkCore.Migrations;
/// <inheritdoc />
public partial class CharacterDataDraft : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Username",
table: "Accounts",
type: "varchar(20)",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(20)");
migrationBuilder.AlterColumn<byte[]>(
name: "Salt",
table: "Accounts",
type: "bytea",
nullable: true,
oldClrType: typeof(byte[]),
oldType: "bytea");
migrationBuilder.AlterColumn<byte[]>(
name: "Password",
table: "Accounts",
type: "bytea",
nullable: true,
oldClrType: typeof(byte[]),
oldType: "bytea");
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "Accounts",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.CreateTable(
name: "Characters",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
ServerId = table.Column<byte>(type: "smallint", nullable: false),
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
MapId = table.Column<int>(type: "integer", nullable: false),
Name = table.Column<string>(type: "varchar(20)", nullable: true),
LastXCoordinate = table.Column<short>(type: "smallint", nullable: false),
LastYCoordinate = table.Column<short>(type: "smallint", nullable: false),
PvPLevel = table.Column<byte>(type: "smallint", nullable: false),
Gender = table.Column<byte>(type: "smallint", nullable: false),
Experience = table.Column<long>(type: "bigint", nullable: false),
Level = table.Column<byte>(type: "smallint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Characters", x => x.Id);
table.ForeignKey(
name: "FK_Characters_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Characters_AccountId",
table: "Characters",
column: "AccountId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Characters");
migrationBuilder.AlterColumn<string>(
name: "Username",
table: "Accounts",
type: "varchar(20)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "varchar(20)",
oldNullable: true);
migrationBuilder.AlterColumn<byte[]>(
name: "Salt",
table: "Accounts",
type: "bytea",
nullable: false,
defaultValue: Array.Empty<byte>(),
oldClrType: typeof(byte[]),
oldType: "bytea",
oldNullable: true);
migrationBuilder.AlterColumn<byte[]>(
name: "Password",
table: "Accounts",
type: "bytea",
nullable: false,
defaultValue: Array.Empty<byte>(),
oldClrType: typeof(byte[]),
oldType: "bytea",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "Accounts",
type: "text",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
}
}

View file

@ -1,184 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231108143729_AddInventoryToCharacter")]
partial class AddInventoryToCharacter
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.Property<byte>("ServerId")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<short>("ItemId")
.HasColumnType("smallint");
b.Property<byte>("ItemType")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItem");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,57 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class AddInventoryToCharacter : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "InventoryItem",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
ItemId = table.Column<short>(type: "smallint", nullable: false),
Count = table.Column<int>(type: "integer", nullable: false),
Slot = table.Column<byte>(type: "smallint", nullable: false),
ItemType = table.Column<byte>(type: "smallint", nullable: false),
Level = table.Column<byte>(type: "smallint", nullable: false),
Rarity = table.Column<byte>(type: "smallint", nullable: false),
AddOption = table.Column<byte>(type: "smallint", nullable: false),
AddOption2 = table.Column<byte>(type: "smallint", nullable: false),
AddOption3 = table.Column<byte>(type: "smallint", nullable: false),
Option = table.Column<short>(type: "smallint", nullable: false),
Option2 = table.Column<short>(type: "smallint", nullable: false),
Option3 = table.Column<short>(type: "smallint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_InventoryItem", x => x.Id);
table.ForeignKey(
name: "FK_InventoryItem_Characters_CharacterId",
column: x => x.CharacterId,
principalTable: "Characters",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_InventoryItem_CharacterId",
table: "InventoryItem",
column: "CharacterId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "InventoryItem");
}
}

View file

@ -1,250 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231113192405_AdditionalCharacterData")]
partial class AdditionalCharacterData
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.Property<byte>("ServerId")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("ItemType")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItem");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Wonderking.Packets.Outgoing.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint");
b1.Property<short>("Intelligence")
.HasColumnType("smallint");
b1.Property<short>("Luck")
.HasColumnType("smallint");
b1.Property<short>("Strength")
.HasColumnType("smallint");
b1.Property<short>("Vitality")
.HasColumnType("smallint");
b1.Property<short>("Wisdom")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,157 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class AdditionalCharacterData : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "ItemId",
table: "InventoryItem",
type: "integer",
nullable: false,
oldClrType: typeof(short),
oldType: "smallint");
migrationBuilder.AddColumn<short>(
name: "BaseStats_Dexterity",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<short>(
name: "BaseStats_Intelligence",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<short>(
name: "BaseStats_Luck",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<short>(
name: "BaseStats_Strength",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<short>(
name: "BaseStats_Vitality",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<short>(
name: "BaseStats_Wisdom",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "Health",
table: "Characters",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<byte>(
name: "JobData_FirstJob",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<byte>(
name: "JobData_FourthJob",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<byte>(
name: "JobData_SecondJob",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<byte>(
name: "JobData_ThirdJob",
table: "Characters",
type: "smallint",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "Mana",
table: "Characters",
type: "integer",
nullable: false,
defaultValue: 0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "BaseStats_Dexterity",
table: "Characters");
migrationBuilder.DropColumn(
name: "BaseStats_Intelligence",
table: "Characters");
migrationBuilder.DropColumn(
name: "BaseStats_Luck",
table: "Characters");
migrationBuilder.DropColumn(
name: "BaseStats_Strength",
table: "Characters");
migrationBuilder.DropColumn(
name: "BaseStats_Vitality",
table: "Characters");
migrationBuilder.DropColumn(
name: "BaseStats_Wisdom",
table: "Characters");
migrationBuilder.DropColumn(
name: "Health",
table: "Characters");
migrationBuilder.DropColumn(
name: "JobData_FirstJob",
table: "Characters");
migrationBuilder.DropColumn(
name: "JobData_FourthJob",
table: "Characters");
migrationBuilder.DropColumn(
name: "JobData_SecondJob",
table: "Characters");
migrationBuilder.DropColumn(
name: "JobData_ThirdJob",
table: "Characters");
migrationBuilder.DropColumn(
name: "Mana",
table: "Characters");
migrationBuilder.AlterColumn<short>(
name: "ItemId",
table: "InventoryItem",
type: "smallint",
nullable: false,
oldClrType: typeof(int),
oldType: "integer");
}
}

View file

@ -1,334 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231114203409_AddGuildData")]
partial class AddGuildData
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.Property<byte>("ServerId")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("ItemType")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItem");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint");
b1.Property<short>("Intelligence")
.HasColumnType("smallint");
b1.Property<short>("Luck")
.HasColumnType("smallint");
b1.Property<short>("Strength")
.HasColumnType("smallint");
b1.Property<short>("Vitality")
.HasColumnType("smallint");
b1.Property<short>("Wisdom")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,126 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class AddGuildData : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "GuildId",
table: "Characters",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateTable(
name: "Guild",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: true),
Notice = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Guild", x => x.Id);
});
migrationBuilder.CreateTable(
name: "GuildMember",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
GuildId = table.Column<Guid>(type: "uuid", nullable: false),
Rank = table.Column<byte>(type: "smallint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_GuildMember", x => x.Id);
table.ForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
column: x => x.CharacterId,
principalTable: "Characters",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_GuildMember_Guild_GuildId",
column: x => x.GuildId,
principalTable: "Guild",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Characters_GuildId",
table: "Characters",
column: "GuildId");
migrationBuilder.CreateIndex(
name: "IX_Characters_Name",
table: "Characters",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Accounts_Username",
table: "Accounts",
column: "Username",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_GuildMember_CharacterId",
table: "GuildMember",
column: "CharacterId");
migrationBuilder.CreateIndex(
name: "IX_GuildMember_GuildId",
table: "GuildMember",
column: "GuildId");
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters");
migrationBuilder.DropTable(
name: "GuildMember");
migrationBuilder.DropTable(
name: "Guild");
migrationBuilder.DropIndex(
name: "IX_Characters_GuildId",
table: "Characters");
migrationBuilder.DropIndex(
name: "IX_Characters_Name",
table: "Characters");
migrationBuilder.DropIndex(
name: "IX_Accounts_Username",
table: "Accounts");
migrationBuilder.DropColumn(
name: "GuildId",
table: "Characters");
}
}

View file

@ -1,334 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231115174714_GuildIsNotRequired")]
partial class GuildIsNotRequired
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.Property<byte>("ServerId")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItem");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint");
b1.Property<short>("Intelligence")
.HasColumnType("smallint");
b1.Property<short>("Luck")
.HasColumnType("smallint");
b1.Property<short>("Strength")
.HasColumnType("smallint");
b1.Property<short>("Vitality")
.HasColumnType("smallint");
b1.Property<short>("Wisdom")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,29 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class GuildIsNotRequired : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "ItemType",
table: "InventoryItem",
newName: "InventoryTab");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "InventoryTab",
table: "InventoryItem",
newName: "ItemType");
}
}

View file

@ -1,323 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231115183824_SwitchToDataAnnotations")]
partial class SwitchToDataAnnotations
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItem");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId");
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint");
b1.Property<short>("Intelligence")
.HasColumnType("smallint");
b1.Property<short>("Luck")
.HasColumnType("smallint");
b1.Property<short>("Strength")
.HasColumnType("smallint");
b1.Property<short>("Vitality")
.HasColumnType("smallint");
b1.Property<short>("Wisdom")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId");
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,232 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class SwitchToDataAnnotations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Guild_GuildId",
table: "GuildMember");
migrationBuilder.DropIndex(
name: "IX_Characters_Name",
table: "Characters");
migrationBuilder.DropColumn(
name: "ServerId",
table: "Characters");
migrationBuilder.AlterColumn<Guid>(
name: "GuildId",
table: "GuildMember",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "GuildMember",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Characters",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(20)",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "GuildId",
table: "Characters",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "AccountId",
table: "Characters",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.CreateIndex(
name: "IX_Accounts_Id",
table: "Accounts",
column: "Id",
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters",
column: "AccountId",
principalTable: "Accounts",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Guild_GuildId",
table: "GuildMember",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Guild_GuildId",
table: "GuildMember");
migrationBuilder.DropIndex(
name: "IX_Accounts_Id",
table: "Accounts");
migrationBuilder.AlterColumn<Guid>(
name: "GuildId",
table: "GuildMember",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "GuildMember",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Characters",
type: "varchar(20)",
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "GuildId",
table: "Characters",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "AccountId",
table: "Characters",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AddColumn<byte>(
name: "ServerId",
table: "Characters",
type: "smallint",
nullable: false,
defaultValue: (byte)0);
migrationBuilder.CreateIndex(
name: "IX_Characters_Name",
table: "Characters",
column: "Name",
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters",
column: "AccountId",
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Guild_GuildId",
table: "GuildMember",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}

View file

@ -1,334 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231116110504_DBPoolingAndLazyLoadingSupport")]
partial class DBPoolingAndLazyLoadingSupport
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItem");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId");
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint");
b1.Property<short>("Intelligence")
.HasColumnType("smallint");
b1.Property<short>("Luck")
.HasColumnType("smallint");
b1.Property<short>("Strength")
.HasColumnType("smallint");
b1.Property<short>("Vitality")
.HasColumnType("smallint");
b1.Property<short>("Wisdom")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId");
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,59 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class DBPoolingAndLazyLoadingSupport : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Characters",
type: "varchar(20)",
maxLength: 20,
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.CreateIndex(
name: "IX_Characters_Id",
table: "Characters",
column: "Id",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Characters_Name",
table: "Characters",
column: "Name",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Characters_Id",
table: "Characters");
migrationBuilder.DropIndex(
name: "IX_Characters_Name",
table: "Characters");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Characters",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(20)",
oldMaxLength: 20,
oldNullable: true);
}
}

View file

@ -1,338 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231120162002_FixInventoryItemAsDbset")]
partial class FixInventoryItemAsDbset
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guilds");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId");
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "dexterity");
b1.Property<short>("Intelligence")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "intelligence");
b1.Property<short>("Luck")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "luck");
b1.Property<short>("Strength")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "strength");
b1.Property<short>("Vitality")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "vitality");
b1.Property<short>("Wisdom")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "wisdom");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId");
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId");
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,166 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class FixInventoryItemAsDbset : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Guild_GuildId",
table: "GuildMember");
migrationBuilder.DropForeignKey(
name: "FK_InventoryItem_Characters_CharacterId",
table: "InventoryItem");
migrationBuilder.DropPrimaryKey(
name: "PK_InventoryItem",
table: "InventoryItem");
migrationBuilder.DropPrimaryKey(
name: "PK_Guild",
table: "Guild");
migrationBuilder.RenameTable(
name: "InventoryItem",
newName: "InventoryItems");
migrationBuilder.RenameTable(
name: "Guild",
newName: "Guilds");
migrationBuilder.RenameIndex(
name: "IX_InventoryItem_CharacterId",
table: "InventoryItems",
newName: "IX_InventoryItems_CharacterId");
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "InventoryItems",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AddPrimaryKey(
name: "PK_InventoryItems",
table: "InventoryItems",
column: "Id");
migrationBuilder.AddPrimaryKey(
name: "PK_Guilds",
table: "Guilds",
column: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guilds",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Guilds_GuildId",
table: "GuildMember",
column: "GuildId",
principalTable: "Guilds",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_InventoryItems_Characters_CharacterId",
table: "InventoryItems",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Guilds_GuildId",
table: "GuildMember");
migrationBuilder.DropForeignKey(
name: "FK_InventoryItems_Characters_CharacterId",
table: "InventoryItems");
migrationBuilder.DropPrimaryKey(
name: "PK_InventoryItems",
table: "InventoryItems");
migrationBuilder.DropPrimaryKey(
name: "PK_Guilds",
table: "Guilds");
migrationBuilder.RenameTable(
name: "InventoryItems",
newName: "InventoryItem");
migrationBuilder.RenameTable(
name: "Guilds",
newName: "Guild");
migrationBuilder.RenameIndex(
name: "IX_InventoryItems_CharacterId",
table: "InventoryItem",
newName: "IX_InventoryItem_CharacterId");
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "InventoryItem",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AddPrimaryKey(
name: "PK_InventoryItem",
table: "InventoryItem",
column: "Id");
migrationBuilder.AddPrimaryKey(
name: "PK_Guild",
table: "Guild",
column: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Guild_GuildId",
table: "GuildMember",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_InventoryItem_Characters_CharacterId",
table: "InventoryItem",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}

View file

@ -1,339 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231121205726_MissingCascadeDeletionOnCharacter")]
partial class MissingCascadeDeletionOnCharacter
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guilds");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId");
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "dexterity");
b1.Property<short>("Intelligence")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "intelligence");
b1.Property<short>("Luck")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "luck");
b1.Property<short>("Strength")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "strength");
b1.Property<short>("Vitality")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "vitality");
b1.Property<short>("Wisdom")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "wisdom");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId");
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId");
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,42 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class MissingCascadeDeletionOnCharacter : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_InventoryItems_Characters_CharacterId",
table: "InventoryItems");
migrationBuilder.AddForeignKey(
name: "FK_InventoryItems_Characters_CharacterId",
table: "InventoryItems",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_InventoryItems_Characters_CharacterId",
table: "InventoryItems");
migrationBuilder.AddForeignKey(
name: "FK_InventoryItems_Characters_CharacterId",
table: "InventoryItems",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id");
}
}

View file

@ -1,353 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231122064508_IndexingAndVariousOtherAnnotations")]
partial class IndexingAndVariousOtherAnnotations
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Guilds");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Restrict);
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "dexterity");
b1.Property<short>("Intelligence")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "intelligence");
b1.Property<short>("Luck")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "luck");
b1.Property<short>("Strength")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "strength");
b1.Property<short>("Vitality")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "vitality");
b1.Property<short>("Wisdom")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "wisdom");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,205 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class IndexingAndVariousOtherAnnotations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Guilds_GuildId",
table: "GuildMember");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Guilds",
type: "character varying(16)",
maxLength: 16,
nullable: true,
oldClrType: typeof(string),
oldType: "text",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Characters",
type: "character varying(20)",
maxLength: 20,
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(20)",
oldMaxLength: 20,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Username",
table: "Accounts",
type: "character varying(20)",
maxLength: 20,
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(20)",
oldMaxLength: 20,
oldNullable: true);
migrationBuilder.CreateIndex(
name: "IX_Guilds_Id",
table: "Guilds",
column: "Id",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Guilds_Name",
table: "Guilds",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_GuildMember_Id",
table: "GuildMember",
column: "Id",
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters",
column: "AccountId",
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guilds",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Guilds_GuildId",
table: "GuildMember",
column: "GuildId",
principalTable: "Guilds",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember");
migrationBuilder.DropForeignKey(
name: "FK_GuildMember_Guilds_GuildId",
table: "GuildMember");
migrationBuilder.DropIndex(
name: "IX_Guilds_Id",
table: "Guilds");
migrationBuilder.DropIndex(
name: "IX_Guilds_Name",
table: "Guilds");
migrationBuilder.DropIndex(
name: "IX_GuildMember_Id",
table: "GuildMember");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Guilds",
type: "text",
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(16)",
oldMaxLength: 16,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Characters",
type: "varchar(20)",
maxLength: 20,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(20)",
oldMaxLength: 20,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Username",
table: "Accounts",
type: "varchar(20)",
maxLength: 20,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(20)",
oldMaxLength: 20,
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters",
column: "AccountId",
principalTable: "Accounts",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guilds",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
table: "GuildMember",
column: "CharacterId",
principalTable: "Characters",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_GuildMember_Guilds_GuildId",
table: "GuildMember",
column: "GuildId",
principalTable: "Guilds",
principalColumn: "Id");
}
}

View file

@ -1,368 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231122091030_VariousDeletionBehaviours")]
partial class VariousDeletionBehaviours
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<Guid?>("GuildMemberId")
.HasColumnType("uuid");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.HasKey("Id");
b.HasIndex("GuildMemberId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Guilds");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid?>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid?>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.GuildMember", "GuildMember")
.WithMany()
.HasForeignKey("GuildMemberId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Restrict);
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "dexterity");
b1.Property<short>("Intelligence")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "intelligence");
b1.Property<short>("Luck")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "luck");
b1.Property<short>("Strength")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "strength");
b1.Property<short>("Vitality")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "vitality");
b1.Property<short>("Wisdom")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "wisdom");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,74 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class VariousDeletionBehaviours : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters");
migrationBuilder.AddColumn<Guid>(
name: "GuildMemberId",
table: "Accounts",
type: "uuid",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Accounts_GuildMemberId",
table: "Accounts",
column: "GuildMemberId");
migrationBuilder.AddForeignKey(
name: "FK_Accounts_GuildMember_GuildMemberId",
table: "Accounts",
column: "GuildMemberId",
principalTable: "GuildMember",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters",
column: "AccountId",
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Accounts_GuildMember_GuildMemberId",
table: "Accounts");
migrationBuilder.DropForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters");
migrationBuilder.DropIndex(
name: "IX_Accounts_GuildMemberId",
table: "Accounts");
migrationBuilder.DropColumn(
name: "GuildMemberId",
table: "Accounts");
migrationBuilder.AddForeignKey(
name: "FK_Characters_Accounts_AccountId",
table: "Characters",
column: "AccountId",
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}

View file

@ -1,348 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
[Migration("20231125112400_FixEntityRelationships")]
partial class FixEntityRelationships
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Guilds");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId")
.IsUnique();
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "dexterity");
b1.Property<short>("Intelligence")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "intelligence");
b1.Property<short>("Luck")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "luck");
b1.Property<short>("Strength")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "strength");
b1.Property<short>("Vitality")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "vitality");
b1.Property<short>("Wisdom")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "wisdom");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithOne("GuildMember")
.HasForeignKey("Continuity.AuthServer.DB.Documents.GuildMember", "CharacterId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("GuildMember");
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,172 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class FixEntityRelationships : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Accounts_GuildMember_GuildMemberId",
table: "Accounts");
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters");
migrationBuilder.DropIndex(
name: "IX_GuildMember_CharacterId",
table: "GuildMember");
migrationBuilder.DropIndex(
name: "IX_Characters_GuildId",
table: "Characters");
migrationBuilder.DropIndex(
name: "IX_Accounts_GuildMemberId",
table: "Accounts");
migrationBuilder.DropColumn(
name: "GuildId",
table: "Characters");
migrationBuilder.DropColumn(
name: "GuildMemberId",
table: "Accounts");
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "InventoryItems",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "GuildId",
table: "GuildMember",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "GuildMember",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "AccountId",
table: "Characters",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.CreateIndex(
name: "IX_GuildMember_CharacterId",
table: "GuildMember",
column: "CharacterId",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_GuildMember_CharacterId",
table: "GuildMember");
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "InventoryItems",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "GuildId",
table: "GuildMember",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "CharacterId",
table: "GuildMember",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "AccountId",
table: "Characters",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AddColumn<Guid>(
name: "GuildId",
table: "Characters",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "GuildMemberId",
table: "Accounts",
type: "uuid",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_GuildMember_CharacterId",
table: "GuildMember",
column: "CharacterId");
migrationBuilder.CreateIndex(
name: "IX_Characters_GuildId",
table: "Characters",
column: "GuildId");
migrationBuilder.CreateIndex(
name: "IX_Accounts_GuildMemberId",
table: "Accounts",
column: "GuildMemberId");
migrationBuilder.AddForeignKey(
name: "FK_Accounts_GuildMember_GuildMemberId",
table: "Accounts",
column: "GuildMemberId",
principalTable: "GuildMember",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guilds_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guilds",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}

View file

@ -1,345 +0,0 @@
// <auto-generated />
using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
partial class WonderkingContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Username")
.IsUnique();
b.ToTable("Accounts");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("Name")
.IsUnique();
b.ToTable("Guilds");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId")
.IsUnique();
b.HasIndex("GuildId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("GuildMember");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<byte>("InventoryTab")
.HasColumnType("smallint");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "dexterity");
b1.Property<short>("Intelligence")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "intelligence");
b1.Property<short>("Luck")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "luck");
b1.Property<short>("Strength")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "strength");
b1.Property<short>("Vitality")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "vitality");
b1.Property<short>("Wisdom")
.HasColumnType("smallint")
.HasAnnotation("Relational:JsonPropertyName", "wisdom");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
b.Navigation("BaseStats");
b.Navigation("JobData");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.GuildMember", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithOne("GuildMember")
.HasForeignKey("Continuity.AuthServer.DB.Documents.GuildMember", "CharacterId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Continuity.AuthServer.DB.Documents.Guild", "Guild")
.WithMany("GuildMembers")
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
b.Navigation("Guild");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.InventoryItem", b =>
{
b.HasOne("Continuity.AuthServer.DB.Documents.Character", "Character")
.WithMany("InventoryItems")
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Character");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b =>
{
b.Navigation("Characters");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Character", b =>
{
b.Navigation("GuildMember");
b.Navigation("InventoryItems");
});
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,19 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.DB.Documents;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
namespace Continuity.AuthServer.DB;
public class WonderkingContext : DbContext
{
public WonderkingContext([NotNull] DbContextOptions options) : base(options)
{
}
public DbSet<Account> Accounts { get; set; }
public DbSet<Character> Characters { get; set; }
public DbSet<InventoryItem> InventoryItems { get; set; }
public DbSet<Guild> Guilds { get; set; }
}

View file

@ -1,27 +0,0 @@
FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine AS base
WORKDIR /app
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
ARG TARGETARCH
ENV TZ=Etc/UTC
ENV DOTNET_TieredPGO=1
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
RUN echo "Target: $TARGETARCH" && echo "Build: $BUILDPLATFORM"
WORKDIR /src
COPY ["Continuity.AuthServer/Continuity.AuthServer.csproj", "Continuity.AuthServer/"]
COPY ["Wonderking/Wonderking.csproj", "Wonderking/"]
RUN dotnet restore "Wonderking/Wonderking.csproj" -a $TARGETARCH && dotnet restore "Continuity.AuthServer/Continuity.AuthServer.csproj" -a $TARGETARCH
COPY . .
FROM build AS publish
RUN dotnet publish "Continuity.AuthServer/Continuity.AuthServer.csproj" -c Release -a $TARGETARCH --no-restore -f net8.0 -o /app
COPY ../config /app/config
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
USER $APP_UID
ENTRYPOINT ["./Continuity.AuthServer"]

View file

@ -1,17 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.PacketHandlers;
using Microsoft.Extensions.Logging;
namespace Continuity.AuthServer.LoggerMessages;
internal static partial class LoginHandlerLoggerMessages
{
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
Message = "Login data: Username {Username} & Password {Password}")]
public static partial void LoginData(this ILogger<LoginHandler> logger, string username, string password);
[LoggerMessage(EventId = 1, Level = LogLevel.Information,
Message = "Requested account for user: {Username} does not exist")]
public static partial void RequestedAccountDoesNotExist(this ILogger<LoginHandler> logger, string username);
}

View file

@ -1,51 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Wonderking.Packets;
namespace Continuity.AuthServer.LoggerMessages;
internal static partial class PacketLoggerMessages
{
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
Message = "Packet creation function created for {PacketID}")]
public static partial void PacketCreationFunctionCreated(this ILogger logger, OperationCode packetId);
[LoggerMessage(EventId = 1, Level = LogLevel.Trace,
Message = "Packet with ID: {PacketID} has been added as {PacketName}")]
public static partial void PacketWithIdAdded(this ILogger logger, OperationCode packetId, string packetName);
[LoggerMessage(EventId = 2, Level = LogLevel.Trace,
Message = "PacketHandler with ID: {PacketID} has been added as {PacketName}")]
public static partial void PacketHandlerWithIdAdded(this ILogger logger, OperationCode packetId,
[CanBeNull] string packetName);
[LoggerMessage(EventId = 3, Level = LogLevel.Information,
Message = "Packet with ID: {PacketID} has been received")]
public static partial void PacketReceived(this ILogger logger, OperationCode packetId);
[LoggerMessage(EventId = 4, Level = LogLevel.Trace,
Message = "[{SessionID}] Packet with ID: {PacketID} is being dequeued")]
public static partial void PacketDequeued(this ILogger logger, Guid sessionId, OperationCode packetId);
[LoggerMessage(EventId = 5, Level = LogLevel.Information,
Message = "Couldn't find Packet type for Id: {PacketID}")]
public static partial void PacketTypeNotFound(this ILogger logger, OperationCode packetId);
[LoggerMessage(EventId = 6, Level = LogLevel.Trace,
Message = "[{SessionID}] Packet with ID: {PacketID} has finished")]
public static partial void PacketFinished(this ILogger logger, Guid sessionId, OperationCode packetId);
[LoggerMessage(EventId = 7, Level = LogLevel.Critical,
Message = "No PacketHandlers have been found")]
public static partial void NoPacketHandlersFound(this ILogger logger);
[LoggerMessage(EventId = 8, Level = LogLevel.Trace,
Message = "Packet data {PacketData}")]
public static partial void PacketData(this ILogger logger, string packetData);
[LoggerMessage(EventId = 9, Level = LogLevel.Critical,
Message = "No Packets have been found")]
public static partial void NoPacketsFound(this ILogger logger);
}

View file

@ -1,23 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.DB.Documents;
using Wonderking.Game.Data.Character;
using Wonderking.Packets.Outgoing.Data;
namespace Continuity.AuthServer.PacketHandlers;
public partial class ChannelSelectionHandler
{
private sealed record InventoryItemProjection(ushort ItemId, byte Slot, InventoryTab InventoryTab);
private sealed record CharacterDataProjection(
string Name,
JobData JobData,
Gender Gender,
ushort Level,
long Experience,
BaseStats BaseStats,
int Health,
int Mana,
IEnumerable<InventoryItemProjection> InventoryItems);
}

View file

@ -1,137 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.DB;
using Continuity.AuthServer.DB.Documents;
using DotNext.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using NetCoreServer;
using Wonderking.Packets.Incoming;
using Wonderking.Packets.Outgoing;
using Wonderking.Packets.Outgoing.Data;
namespace Continuity.AuthServer.PacketHandlers;
public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
{
private readonly WonderkingContext _wonderkingContext;
public ChannelSelectionHandler(WonderkingContext wonderkingContext)
{
_wonderkingContext = wonderkingContext;
}
public async Task HandleAsync(ChannelSelectionPacket packet, TcpSession session)
{
if (session is not AuthSession authSession)
{
return;
}
ChannelSelectionResponsePacket responsePacket;
var guildNameResponsePacket = new CharacterSelectionSetGuildNamePacket { GuildNames = Array.Empty<string>() };
var accountExists =
await _wonderkingContext.Accounts.AsNoTracking().AnyAsync(a => a.Id == authSession.AccountId);
var amountOfCharacter = await _wonderkingContext.Characters.AsNoTracking().Include(c => c.Account)
.Where(c => c.Account.Id == authSession.AccountId).Take(3)
.CountAsync();
if (!accountExists)
{
return;
}
if (amountOfCharacter > 0)
{
responsePacket = new ChannelSelectionResponsePacket
{
ChannelIsFullFlag = 0,
Endpoint = "127.0.0.1",
Port = 2000,
Characters = await GetCharacterDataAsync(authSession.AccountId).ToArrayAsync()
};
guildNameResponsePacket.GuildNames =
await _wonderkingContext.Characters.AsNoTracking().Include(c => c.Account).Include(c => c.GuildMember)
.ThenInclude(gm => gm.Guild)
.Where(c => c.Account.Id == authSession.AccountId && c.GuildMember.Guild != null)
.Select(c => c.GuildMember.Guild.Name).Take(3).ToArrayAsync();
}
else
{
responsePacket = new ChannelSelectionResponsePacket
{
ChannelIsFullFlag = 0,
Endpoint = "127.0.0.1",
Port = 2000,
Characters = Array.Empty<CharacterData>()
};
}
await authSession.SendAsync(responsePacket);
if (guildNameResponsePacket.GuildNames.Length > 0 &&
guildNameResponsePacket.GuildNames.Select(n => n != string.Empty).Any())
{
await authSession.SendAsync(guildNameResponsePacket);
}
}
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<InventoryItemProjection> items)
{
var ids = new ushort[20];
ids.AsSpan().Clear();
foreach (var item in items)
{
if (item.Slot > 20)
{
continue;
}
ids[item.Slot] = item.ItemId;
}
return ids;
}
private async IAsyncEnumerable<CharacterData> GetCharacterDataAsync(Guid accountId)
{
var characterDataProjections = _wonderkingContext.Characters.AsNoTracking().AsSplitQuery()
.Include(c => c.InventoryItems).Include(c => c.Account)
.Where(c => c.Account.Id == accountId)
.Select(c => new CharacterDataProjection(
c.Name,
c.JobData,
c.Gender,
c.Level,
c.Experience,
c.BaseStats,
c.Health,
c.Mana,
c.InventoryItems.Select(i =>
new InventoryItemProjection(i.ItemId, i.Slot, i.InventoryTab))
)).Take(3);
await foreach (var c in characterDataProjections)
{
yield return new CharacterData
{
Name = c.Name,
Job = c.JobData,
Gender = c.Gender,
Level = c.Level,
// TODO: Calculate instead of clamping based on max experience for level
Experience = Math.Clamp(c.Experience, 0, 100),
Stats = c.BaseStats,
Health = c.Health,
Mana = c.Mana,
EquippedItems =
GetItemIDsByInventoryTab(c.InventoryItems.Where(i =>
i.InventoryTab == InventoryTab.WornEquipment)),
EquippedCashItems = GetItemIDsByInventoryTab(c.InventoryItems.Where(i =>
i.InventoryTab == InventoryTab.WornCashEquipment))
};
}
}
}

View file

@ -1,176 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.DB;
using Continuity.AuthServer.DB.Documents;
using Continuity.AuthServer.Services;
using Microsoft.EntityFrameworkCore;
using NetCoreServer;
using Wonderking.Game.Data.Character;
using Wonderking.Game.Mapping;
using Wonderking.Packets.Incoming;
using Wonderking.Packets.Outgoing;
using Wonderking.Packets.Outgoing.Data;
namespace Continuity.AuthServer.PacketHandlers;
public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
{
private readonly CharacterStatsMappingConfiguration _characterStatsMapping;
private readonly ItemObjectPoolService _itemObjectPoolService;
private readonly WonderkingContext _wonderkingContext;
public CharacterCreationHandler(WonderkingContext wonderkingContext, ItemObjectPoolService itemObjectPoolService,
CharacterStatsMappingConfiguration characterStatsMappingConfiguration)
{
_wonderkingContext = wonderkingContext;
_itemObjectPoolService = itemObjectPoolService;
_characterStatsMapping = characterStatsMappingConfiguration;
}
public async Task HandleAsync(CharacterCreationPacket packet, TcpSession session)
{
if (session is not AuthSession authSession)
{
return;
}
var account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Id == authSession.AccountId);
if (account is null)
{
return;
}
var firstJobConfig = SelectFirstJobConfig(packet.FirstJob);
var items = CreateDefaultItems(packet, firstJobConfig);
var toBeAddedCharacter = CreateDefaultCharacter(packet, account, items, firstJobConfig);
account.Characters.Add(toBeAddedCharacter);
await _wonderkingContext.SaveChangesAsync();
var character =
new CharacterData
{
Name = toBeAddedCharacter.Name,
Job = toBeAddedCharacter.JobData,
Gender = toBeAddedCharacter.Gender,
Level = toBeAddedCharacter.Level,
Experience = toBeAddedCharacter.Experience,
Stats = toBeAddedCharacter.BaseStats,
Health = toBeAddedCharacter.Health,
Mana = toBeAddedCharacter.Mana,
EquippedItems =
GetItemIDsByInventoryTab(toBeAddedCharacter.InventoryItems
.Where(item => item.InventoryTab == InventoryTab.WornEquipment)
.Select(item => new Tuple<ushort, byte>(item.ItemId, item.Slot)).AsEnumerable()),
EquippedCashItems = GetItemIDsByInventoryTab(toBeAddedCharacter.InventoryItems
.Where(item => item.InventoryTab == InventoryTab.WornCashEquipment)
.Select(item => new Tuple<ushort, byte>(item.ItemId, item.Slot)).AsEnumerable())
};
await authSession.SendAsync(new CharacterCreationResponsePacket
{
Character = character,
Slot = packet.Slot,
isDuplicate = false
});
}
private InventoryItem[] CreateDefaultItems(CharacterCreationPacket packet, JobSpecificMapping firstJobConfig)
{
var mappedDefaultItems = _characterStatsMapping.DefaultCharacterMapping.Items
.Select(i => _itemObjectPoolService.GetBaseInventoryItem(i.Id, i.Quantity)).ToArray();
var mappedJobItems = firstJobConfig.Items
.Select(i => _itemObjectPoolService.GetBaseInventoryItem(i.Id, i.Quantity)).ToArray();
var defaultItems = CreateChosenItems(packet);
InventoryItem[] items =
[
.. mappedDefaultItems,
.. mappedJobItems,
.. defaultItems
];
return items;
}
private static Character CreateDefaultCharacter(CharacterCreationPacket packet, Account account,
InventoryItem[] items, JobSpecificMapping firstJobConfig)
{
return new Character()
{
Account = account,
MapId = 300,
Name = packet.Name,
LastXCoordinate = 113,
LastYCoordinate = 0,
PvPLevel = PvPLevel.None,
Gender = packet.Gender,
Experience = 0,
Level = 1,
InventoryItems = items,
BaseStats = firstJobConfig.BaseStats,
JobData = new JobData { FirstJob = packet.FirstJob, SecondJob = 0, ThirdJob = 0, FourthJob = 0 },
Health = CalculateCurrentHealth(1, firstJobConfig),
Mana = CalculateCurrentMana(1, firstJobConfig)
};
}
private JobSpecificMapping SelectFirstJobConfig(byte firstJob)
{
return firstJob switch
{
1 => _characterStatsMapping.Swordsman,
2 => _characterStatsMapping.Mage,
3 => _characterStatsMapping.Thief,
4 => _characterStatsMapping.Scout,
_ => _characterStatsMapping.Swordsman
};
}
private InventoryItem[] CreateChosenItems(CharacterCreationPacket packet)
{
return new[]
{
_itemObjectPoolService.GetBaseInventoryItem((ushort)((packet.FirstJob - 1) * 6 +
((byte)packet.Gender - 1) * 3 +
packet.Hair + 1)),
_itemObjectPoolService.GetBaseInventoryItem((ushort)((packet.FirstJob - 1) * 6 +
((byte)packet.Gender - 1) * 3 +
packet.Eyes + 25)),
_itemObjectPoolService.GetBaseInventoryItem((ushort)(((byte)packet.Gender - 1) * 3 +
packet.Shirt + 49)),
_itemObjectPoolService.GetBaseInventoryItem((ushort)(((byte)packet.Gender - 1) * 3 +
packet.Pants + 58))
};
}
private static int CalculateCurrentHealth(ushort level, JobSpecificMapping firstJobConfig)
{
return (int)((level - 1) * firstJobConfig.DynamicStats.HealthPerLevel +
firstJobConfig.BaseStats.Vitality * firstJobConfig.DynamicStats.HealthPerVitality);
}
private static int CalculateCurrentMana(ushort level, JobSpecificMapping firstJobConfig)
{
return (int)((level - 1) * firstJobConfig.DynamicStats.ManaPerLevel +
firstJobConfig.BaseStats.Wisdom * firstJobConfig.DynamicStats.ManaPerWisdom);
}
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<Tuple<ushort, byte>> items)
{
Span<ushort> ids = stackalloc ushort[20];
ids.Clear();
foreach (var item in items)
{
if (item.Item2 > 20)
{
continue;
}
ids[item.Item2] = item.Item1;
}
return ids.ToArray();
}
}

View file

@ -1,43 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using NetCoreServer;
using Wonderking.Packets.Incoming;
using Wonderking.Packets.Outgoing;
namespace Continuity.AuthServer.PacketHandlers;
public class CharacterDeletionHandler : IPacketHandler<CharacterDeletePacket>
{
private readonly WonderkingContext _wonderkingContext;
public CharacterDeletionHandler(WonderkingContext wonderkingContext)
{
_wonderkingContext = wonderkingContext;
}
public async Task HandleAsync(CharacterDeletePacket packet, TcpSession session)
{
if (session is not AuthSession authSession)
{
session.Disconnect();
return;
}
var character = await _wonderkingContext.Characters.FirstOrDefaultAsync(x => x.Name == packet.Name &&
x.Account.Id == authSession.AccountId);
var response = new CharacterDeleteResponsePacket { HasToBeZero = 0 };
if (character == null)
{
await authSession.SendAsync(response);
return;
}
_wonderkingContext.Characters.Remove(character);
await _wonderkingContext.SaveChangesAsync();
await authSession.SendAsync(response);
}
}

View file

@ -1,12 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Runtime.InteropServices;
namespace Continuity.AuthServer.PacketHandlers;
[StructLayout(LayoutKind.Auto)]
public struct CharacterMappingItemEntry
{
public required ushort Id { get; set; }
public required ushort Quantity { get; set; }
}

View file

@ -1,29 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore;
using NetCoreServer;
using Wonderking.Packets.Incoming;
using Wonderking.Packets.Outgoing;
namespace Continuity.AuthServer.PacketHandlers;
public class CharacterNameCheckHandler : IPacketHandler<CharacterNameCheckPacket>
{
private readonly WonderkingContext _wonderkingContext;
public CharacterNameCheckHandler(WonderkingContext wonderkingContext)
{
_wonderkingContext = wonderkingContext;
}
public async Task HandleAsync(CharacterNameCheckPacket packet, TcpSession session)
{
var isTaken = await _wonderkingContext.Characters.AnyAsync(c => c.Name == packet.Name);
var responsePacket = new CharacterNameCheckPacketResponse { IsTaken = isTaken };
if (session is AuthSession authSession)
{
await authSession.SendAsync(responsePacket);
}
}
}

View file

@ -1,37 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Diagnostics;
using JetBrains.Annotations;
using NetCoreServer;
using Wonderking.Packets;
namespace Continuity.AuthServer.PacketHandlers;
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public interface IPacketHandler<in T> : IPacketHandler where T : IPacket
{
[UsedImplicitly]
public Task HandleAsync(T packet, TcpSession session);
async Task<bool> IPacketHandler.TryHandleAsync(IPacket packet, TcpSession session)
{
if (packet is not T tPacket)
{
return false;
}
using (var activity = new ActivitySource(nameof(Server)).StartActivity("HandleAsync"))
{
activity?.SetTag("Handler", this.ToString());
activity?.SetTag("PacketId", packet.ToString());
await HandleAsync(tPacket, session);
}
return true;
}
}
public interface IPacketHandler
{
Task<bool> TryHandleAsync(IPacket packet, TcpSession session);
}

View file

@ -1,129 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using Continuity.AuthServer.DB;
using Continuity.AuthServer.DB.Documents;
using Continuity.AuthServer.LoggerMessages;
using Konscious.Security.Cryptography;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NetCoreServer;
using Wonderking.Packets.Incoming;
using Wonderking.Packets.Outgoing;
using Wonderking.Packets.Outgoing.Data;
namespace Continuity.AuthServer.PacketHandlers;
public class LoginHandler : IPacketHandler<LoginInfoPacket>
{
private readonly IConfiguration _configuration;
private readonly ILogger<LoginHandler> _logger;
private readonly WonderkingContext _wonderkingContext;
private static readonly ActivitySource _activitySource = new ActivitySource(nameof(Server));
public LoginHandler(ILogger<LoginHandler> logger, WonderkingContext wonderkingContext, IConfiguration configuration)
{
_logger = logger;
_wonderkingContext = wonderkingContext;
_configuration = configuration;
}
public async Task HandleAsync(LoginInfoPacket packet, TcpSession session)
{
LoginResponseReason loginResponseReason;
_logger.LoginData(packet.Username, packet.Password);
var account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username);
if (account == null)
{
if (_configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin"))
{
loginResponseReason = await CreateAccountOnLoginAsync(packet.Username, packet.Password);
account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username);
}
else
{
_logger.RequestedAccountDoesNotExist(packet.Username);
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
}
}
else
{
var salt = account.Salt;
var tempPasswordBytes = await GetPasswordHashAsync(packet.Password, salt, account.Id);
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
? LoginResponseReason.Ok
: LoginResponseReason.WrongPassword;
}
var channelData = new ServerChannelData[1];
channelData[0] = new ServerChannelData { ChannelId = 0, LoadPercentage = 0, ServerId = 0 };
var loginResponsePacket = new LoginResponsePacket
{
ResponseReason = loginResponseReason,
ChannelData = channelData.ToArray(),
UnknownFlag = 1,
IsGameMaster = true
};
var authSession = session as AuthSession;
if (account != null && authSession != null)
{
authSession.AccountId = account.Id;
}
_logger.LogInformation("LoginResponsePacket: {@LoginResponsePacket}", loginResponsePacket);
_ = authSession?.SendAsync(loginResponsePacket);
}
private static async Task<byte[]> GetPasswordHashAsync(string password, byte[] salt, Guid userId)
{
using var activity = _activitySource.StartActivity("GetPasswordHashAsync");
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Chea1t_Sheet.html#argon2id
// "Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism."
var argon2Id = new Argon2id(Encoding.ASCII.GetBytes(password))
{
MemorySize = 1024 * 19,
Iterations = 2,
DegreeOfParallelism = 1,
Salt = salt,
AssociatedData = userId.ToByteArray()
};
return await argon2Id.GetBytesAsync(16);
}
private async Task<LoginResponseReason> CreateAccountOnLoginAsync(string username, string password)
{
using var activity = _activitySource.StartActivity("CreateAccountOnLoginAsync");
LoginResponseReason loginResponseReason;
var transaction =
await _wonderkingContext.Database.BeginTransactionAsync();
await using (transaction)
{
try
{
var salt = RandomNumberGenerator.GetBytes(16);
var finalAccount = await _wonderkingContext.Accounts.AddAsync(new Account(username,
Array.Empty<byte>(), "", 0, salt));
await _wonderkingContext.SaveChangesAsync();
finalAccount.Entity.Password =
await GetPasswordHashAsync(password, salt, finalAccount.Entity.Id);
_wonderkingContext.Accounts.Update(finalAccount.Entity);
loginResponseReason = LoginResponseReason.Ok;
await _wonderkingContext.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception)
{
await transaction.RollbackAsync(); // Rollback the transaction on error
throw;
}
}
return loginResponseReason;
}
}

View file

@ -1,127 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Net;
using System.Reflection;
using System.Text.Json;
using Continuity.AuthServer.DB;
using Continuity.AuthServer.Services;
using MassTransit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Npgsql;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Wonderking.Game.Mapping;
var builder = Host.CreateApplicationBuilder();
#if DEBUG
builder.Environment.EnvironmentName = "Development";
#endif
builder.Services.AddMetrics();
builder.Configuration.AddJsonFile("settings.json", true, true)
.AddJsonFile($"settings.{builder.Environment.EnvironmentName}.json", true)
.AddEnvironmentVariables().Build();
builder.Services.AddLogging();
var loggerFactory = LoggerFactory.Create(loggingBuilder =>
{
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.log", LogLevel.Trace);
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.json.log", LogLevel.Trace, isJson: true);
loggingBuilder.AddConsole();
});
var configuration = builder.Configuration;
if (configuration.GetValue<bool>("Tracing:Enabled"))
{
Action<ResourceBuilder> resourceBuilderAction = r => r
.AddService("Continuity", serviceInstanceId: Environment.MachineName);
builder.Services.AddOpenTelemetry()
.ConfigureResource(resourceBuilderAction)
.WithTracing(tracing =>
{
tracing.AddSource(nameof(Server));
//tracing.AddSource("MassTransit");
tracing.AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true);
tracing.AddNpgsql();
})
.WithMetrics(metrics =>
{
metrics.AddRuntimeInstrumentation();
metrics.AddProcessInstrumentation();
});
builder.Logging.AddOpenTelemetry(logging =>
{
var resourceBuilder = ResourceBuilder.CreateDefault();
resourceBuilderAction(resourceBuilder);
logging.SetResourceBuilder(resourceBuilder);
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
builder.Services.Configure<OpenTelemetryLoggerOptions>(logging =>
{
logging.AddOtlpExporter(options =>
{
options.Endpoint = new Uri(configuration["OTLP:Logging:Endpoint"] ?? string.Empty);
});
});
builder.Services.ConfigureOpenTelemetryMeterProvider(metrics =>
{
metrics.AddOtlpExporter(options =>
options.Endpoint = new Uri(configuration["OTLP:Metrics:Endpoint"] ?? string.Empty));
});
builder.Services.ConfigureOpenTelemetryTracerProvider(tracing =>
{
tracing.AddZipkinExporter(options =>
options.Endpoint = new Uri(configuration["Zipkin:Endpoint"] ?? string.Empty));
tracing.AddOtlpExporter(options => options.Endpoint = new Uri(configuration["OTLP:Tracing:Endpoint"] ?? string.Empty));
});
}
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
builder.Services.AddDbContextPool<WonderkingContext>(o =>
{
o.UseNpgsql(
$"Host={configuration["DB:Host"]};Username={configuration["DB:Username"]};Password={configuration["DB:Password"]};Database={configuration["DB:Database"]};Port={configuration["DB:Port"]}")
.EnableSensitiveDataLogging().UseLazyLoadingProxies().UseLoggerFactory(loggerFactory);
});
builder.Services.AddSingleton<CharacterStatsMappingConfiguration>(
JsonSerializer.Deserialize<CharacterStatsMappingConfiguration>(
File.ReadAllText("config/character-stats.mapping.json")) ?? throw new InvalidOperationException());
builder.Services.AddSingleton<ILoggerFactory>(loggerFactory);
builder.Services.AddSingleton<PacketDistributorService>();
builder.Services.AddSingleton<ItemObjectPoolService>();
builder.Services.AddHostedService(provider =>
provider.GetService<ItemObjectPoolService>() ?? throw new InvalidOperationException());
builder.Services.AddHostedService(provider =>
provider.GetService<PacketDistributorService>() ?? throw new InvalidOperationException());
builder.Services.AddMassTransit(x =>
{
x.UsingInMemory((context, configurator) => configurator.ConfigureEndpoints(context));
x.AddMediator(cfg => cfg.AddConsumers(Assembly.GetExecutingAssembly()));
});
builder.Services.AddHostedService(provider => new WonderkingAuthServer(IPAddress.Any, 10001,
provider.GetService<ILogger<WonderkingAuthServer>>() ?? throw new InvalidOperationException(),
provider.GetService<IServiceProvider>() ?? throw new InvalidOperationException()));
using var host = builder.Build();
using (var scope = host.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<WonderkingContext>();
await db.Database.MigrateAsync();
}
await host.RunAsync();

View file

@ -1,98 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Collections.Concurrent;
using Continuity.AuthServer.DB.Documents;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Wonderking.Game.Data;
using Wonderking.Game.Reader;
namespace Continuity.AuthServer.Services;
public class ItemObjectPoolService : IHostedService
{
private readonly ConcurrentDictionary<uint, ItemObject> _itemObjectPool;
private readonly ItemReader _itemReader;
private readonly ILogger<ItemObjectPoolService> _logger;
public ItemObjectPoolService(IConfiguration configuration, ILogger<ItemObjectPoolService> logger)
{
_logger = logger;
_itemReader = new ItemReader(configuration.GetSection("Game").GetSection("Data").GetValue<string>("Path") ??
string.Empty);
_itemObjectPool = new ConcurrentDictionary<uint, ItemObject>();
}
public Task StartAsync(CancellationToken cancellationToken)
{
var amountOfEntries = _itemReader.GetAmountOfEntries();
Parallel.For(0, (int)amountOfEntries, i =>
{
var itemObject = _itemReader.GetEntry((uint)i);
var result = _itemObjectPool.TryAdd(itemObject.ItemID, itemObject);
if (!result)
{
throw new KeyNotFoundException($"Failed to add item {itemObject.ItemID} to the item object pool");
}
_logger.LogTrace("Item with {ID} has been added", itemObject.ItemID);
});
_logger.LogInformation("A total of {AmountOfEntries} items have been added to the item object pool",
_itemObjectPool.Count);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public ItemObject GetItem(ushort itemId)
{
_ = _itemObjectPool.TryGetValue(itemId, out var itemObject);
return itemObject;
}
public bool ContainsItem(ushort itemId)
{
return _itemObjectPool.ContainsKey(itemId);
}
public IQueryable<ItemObject> QueryItems()
{
return _itemObjectPool.AsReadOnly().Values.AsQueryable();
}
public InventoryItem GetBaseInventoryItem(ushort itemId, ushort count = 1, bool isWorn = false)
{
var item = GetItem(itemId);
return new InventoryItem
{
ItemId = itemId,
Count = count,
Slot = (byte)item.SlotNo1,
InventoryTab =
item.ItemType switch
{
1 => InventoryTab.WornCashEquipment,
2 => isWorn ? InventoryTab.WornEquipment : InventoryTab.Equipment,
3 => InventoryTab.Etc,
4 => isWorn ? InventoryTab.WornCashEquipment : InventoryTab.Cash,
5 => InventoryTab.Warehouse,
0 => InventoryTab.WornEquipment,
_ => InventoryTab.WornEquipment
},
Level = item.MinimumLevelRequirement,
Rarity = 0,
AddOption = 0,
AddOption2 = 0,
AddOption3 = 0,
Option = 0,
Option2 = 0,
Option3 = 0
};
}
}

View file

@ -1,187 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection;
using Continuity.AuthServer.LoggerMessages;
using Continuity.AuthServer.PacketHandlers;
using Continuity.AuthServer.Packets;
using DotNext.Collections.Generic;
using DotNext.Linq.Expressions;
using DotNext.Metaprogramming;
using MassTransit.Internals;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
using Wonderking.Packets;
namespace Continuity.AuthServer.Services;
using static CodeGenerator;
using static ExpressionBuilder;
public class PacketDistributorService : IHostedService, IDisposable
{
private readonly ConcurrentQueue<RawPacket> _concurrentQueue;
private readonly ILogger<PacketDistributorService> _logger;
private readonly IServiceProvider _serviceProvider;
private ImmutableDictionary<OperationCode,
Func<byte[], IPacket>> _deserializationMap;
private ConcurrentDictionary<OperationCode, IPacketHandler> _packetHandlersInstantiation;
private readonly ActivitySource _activitySource;
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
{
_concurrentQueue = new ConcurrentQueue<RawPacket>();
_logger = logger;
_serviceProvider = serviceProvider;
_activitySource = new ActivitySource(nameof(Server));
}
public Task StartAsync(CancellationToken cancellationToken)
{
var tempDeserializationMap =
new Dictionary<OperationCode, Func<byte[], IPacket>>();
var wonderkingAssembly = Assembly.GetAssembly(typeof(IPacket));
var packetsTypes = GetPacketsWithId(wonderkingAssembly);
var packetHandlers = GetAllPacketHandlersWithId(Assembly.GetExecutingAssembly());
_packetHandlersInstantiation = new ConcurrentDictionary<OperationCode, IPacketHandler>();
packetHandlers.ForEach(x =>
{
var packetHandler =
ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider,
x.Value);
_packetHandlersInstantiation.TryAdd(x.Key, packetHandler as IPacketHandler);
});
foreach (var packetsType in packetsTypes)
{
var lambda = Lambda<Func<byte[], IPacket>>(fun =>
{
var argPacketData = fun[0];
var newPacket = packetsType.Value.New();
var packetVariable = DeclareVariable(packetsType.Value, "packet");
Assign(packetVariable, newPacket);
Call(packetVariable, nameof(IPacket.Deserialize), argPacketData);
Return(packetVariable);
}).Compile();
_logger.PacketCreationFunctionCreated(packetsType.Key);
tempDeserializationMap.Add(packetsType.Key, lambda);
}
_deserializationMap = tempDeserializationMap.ToImmutableDictionary();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
private Dictionary<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
{
// ! : We are filtering if types that don't have an instance of the required Attribute
var packetsWithId = executingAssembly.GetTypes().AsParallel()
.Where(type => type.HasInterface(typeof(IPacket)) && type is { IsInterface: false, IsAbstract: false })
.Where(type => type.Namespace?.Contains("Incoming") ?? false)
.Select(type => new { Type = type, Attribute = type.GetCustomAttribute<PacketIdAttribute>() })
.Where(item => item.Attribute is not null)
.ToDictionary(item => item.Attribute!.Code, item => item.Type);
if (packetsWithId is not { Count: 0 })
{
packetsWithId.AsParallel()
.ForAll(packet => _logger.PacketWithIdAdded(packet.Key, packet.Value.FullName));
return packetsWithId;
}
_logger.NoPacketsFound();
throw new IncompleteInitialization();
}
private Dictionary<OperationCode, Type> GetAllPacketHandlersWithId(Assembly assembly)
{
// ! : We are filtering if types that don't have an instance of the required Attribute
var packetHandlersWithId = assembly.GetTypes().AsParallel()
.Where(t =>
t is { IsClass: true, IsAbstract: false } && Array.Exists(t
.GetInterfaces(), i =>
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketHandler<>)))
.Select(type => new
{
Type = type,
PacketId = type
.GetInterfaces().First(t1 =>
t1 is { IsGenericType: true } && t1.GetGenericTypeDefinition() == typeof(IPacketHandler<>))
.GetGenericArguments()[0].GetCustomAttribute<PacketIdAttribute>()?.Code
})
.Where(x => x.PacketId is not null)
.ToDictionary(
x => x.PacketId!.Value, x => x.Type
);
if (packetHandlersWithId is not { Count: 0 })
{
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
_logger.PacketHandlerWithIdAdded(packetHandler.Key, packetHandler.Value.FullName));
return packetHandlersWithId;
}
_logger.NoPacketHandlersFound();
throw new IncompleteInitialization();
}
public void AddPacket(RawPacket rawPacket)
{
_concurrentQueue.Enqueue(rawPacket);
DequeueRawPacket();
_logger.PacketReceived(rawPacket.OperationCode);
}
private void DequeueRawPacket()
{
if (_concurrentQueue.TryDequeue(out var item))
{
ThreadPool.QueueUserWorkItem(InvokePacketHandler, item, preferLocal: false);
}
}
private void InvokePacketHandler(RawPacket item)
{
IPacket packet;
_logger.PacketDequeued(item.Session.Id, item.OperationCode);
if (!_deserializationMap.TryGetValue(item.OperationCode, out var value))
{
_logger.PacketTypeNotFound(item.OperationCode);
return;
}
using (var packetParsingActivity = _activitySource.StartActivity("PacketParsing"))
{
packetParsingActivity?.SetTag("PacketId", item.OperationCode);
packet = value(item.MessageBody);
}
using (var packetHandlerActivity = _activitySource.StartActivity("PacketHandler"))
{
packetHandlerActivity?.SetTag("PacketId", item.OperationCode);
_ = _packetHandlersInstantiation[item.OperationCode].TryHandleAsync(packet, item.Session);
}
_logger.PacketData(JsonConvert.SerializeObject(packet));
_logger.PacketFinished(item.Session.Id, item.OperationCode);
}
public void Dispose()
{
GC.SuppressFinalize(this);
_activitySource.Dispose();
}
}

View file

@ -1,82 +0,0 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NetCoreServer;
namespace Continuity.AuthServer.Services;
public class WonderkingAuthServer : TcpServer, IHostedService
{
private readonly ILogger<WonderkingAuthServer> _logger;
private readonly IServiceProvider _serviceProvider;
public WonderkingAuthServer(IPAddress address, int port, ILogger<WonderkingAuthServer> logger,
IServiceProvider serviceProvider) : base(address, port)
{
_logger = logger;
_serviceProvider = serviceProvider;
}
public Task StartAsync(CancellationToken cancellationToken)
{
Start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
DisconnectAll();
Stop();
return Task.CompletedTask;
}
protected override TcpSession CreateSession()
{
return ActivatorUtilities.CreateInstance<AuthSession>(_serviceProvider, this);
}
protected override void OnStarting()
{
_logger.LogInformation("Starting");
base.OnStarting();
}
protected override void OnStarted()
{
_logger.LogInformation("Started");
base.OnStarted();
}
protected override void OnStopping()
{
_logger.LogInformation("Stopping");
base.OnStopping();
}
protected override void OnStopped()
{
_logger.LogInformation("Stopped");
base.OnStopped();
}
protected override void OnConnected(TcpSession session)
{
_logger.LogInformation("Client connected {Session}", session.Id);
base.OnConnected(session);
}
protected override void OnDisconnected(TcpSession session)
{
_logger.LogInformation("Client disconnected {Session}", session.Id);
base.OnDisconnected(session);
}
protected override void OnError(SocketError error)
{
_logger.LogError("An error has occured {Error}", error);
}
}

View file

@ -1,17 +0,0 @@
{
"DB": {
"Username": "continuity",
"Host": "localhost",
"Password": "continuity",
"Database": "continuity",
"Port": "5432"
},
"Testing": {
"CreateAccountOnLogin": true
},
"Game": {
"Data": {
"Path": "../wk-data/"
}
}
}

View file

@ -1,11 +1,9 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Continuity.AuthServer", "Continuity.AuthServer\Continuity.AuthServer.csproj", "{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{7D560FA1-A61C-4B67-8300-835CA5814621}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{7D560FA1-A61C-4B67-8300-835CA5814621}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wonderking", "Wonderking\Wonderking.csproj", "{6B53A10B-C397-4347-BB00-A12272D0528E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -20,9 +18,5 @@ Global
{7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.Build.0 = Debug|Any CPU {7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.Build.0 = Release|Any CPU {7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.Build.0 = Release|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=decryptor/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -1,6 +1,2 @@
# What is this project about? # What is this project about?
This is a continuation and rewrite of the original Project Infinity for Wonderking. This is a continuation and rewrite of the original Project Infinity for Wonderking.
## Important notes for developers
* Avoid using statements with TcpSession, AuthSession or any type that inherits Session outside the session itself.

98
Server/AuthSession.cs Normal file
View file

@ -0,0 +1,98 @@
namespace Server;
using System.Reflection;
using MassTransit.Mediator;
using Microsoft.Extensions.Logging;
using NetCoreServer;
using Packets;
public class AuthSession : TcpSession
{
private readonly ILogger<AuthSession> logger;
private readonly IMediator mediator;
public AuthSession(TcpServer
server, IMediator mediator, ILogger<AuthSession> logger) : base(server)
{
this.mediator = mediator;
this.logger = logger;
}
public override long Send(byte[] buffer)
{
this.logger.LogInformation("Data being sent is: {Data}", BitConverter.ToString(buffer));
return base.Send(buffer);
}
public void Send(IPacket packet)
{
var type = packet.GetType();
this.logger.LogTrace("Packet of type {Type} is being serialized", type.Name);
var packetIdAttribute = type.GetCustomAttribute<PacketIdAttribute>();
if (packetIdAttribute == null)
{
return;
}
var opcode = packetIdAttribute.Code;
Span<byte> packetData = packet.Serialize();
var length = (ushort)(packetData.Length + 8);
Span<byte> buffer = stackalloc byte[length];
buffer.Clear();
packetData.CopyTo(buffer.Slice(8, length - 8));
var bytesOfLength = BitConverter.GetBytes(length);
var bytesOfOpcode = BitConverter.GetBytes((ushort)opcode);
for (var i = 0; i < bytesOfLength.Length || i < 2; i++)
{
buffer[i] = bytesOfLength[i];
}
for (var i = 0; i < bytesOfOpcode.Length || i < 2; i++)
{
buffer[2 + i] = bytesOfOpcode[i];
}
this.logger.LogTrace("Packet data being parsed is: {Data}", BitConverter.ToString(packetData.ToArray()));
this.logger.LogTrace("Packet being parsed is: {Data}", BitConverter.ToString(buffer.ToArray()));
this.Send(buffer);
}
protected override void OnReceived(byte[] buffer, long offset, long size)
{
this.logger.LogDebug("Length: {Size} & offset: {Offset}", size, offset);
Span<byte> decryptedBuffer = new byte[size];
// xor every value after the first 8 bytes
var dataBuffer = Decrypt(new ArraySegment<byte>(buffer, 8, (int)size - 8).ToArray());
this.logger.LogDebug("Length {length}", BitConverter.ToUInt16(buffer, 0));
var opCode = BitConverter.ToUInt16(buffer.ToArray(), 2);
this.logger.LogDebug("Packet Op Code: {OpCode}", opCode);
this.logger.LogDebug("Some Value: {RandomValue}", buffer[4]);
var clientAliveTime = BitConverter.ToUInt16(buffer.ToArray(), 5);
this.logger.LogDebug("Client Alive time: {ClientAliveTime}", clientAliveTime);
this.logger.LogDebug("Might be a flag: {Flag}", buffer[7]);
this.logger.LogDebug("Full buffer: {Buffer}", BitConverter.ToString(dataBuffer.ToArray()));
var rawPacket = new RawPacket((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[7],
buffer[4], this.Id, this);
Task.Run(() => this.mediator.Send(rawPacket));
this.logger.LogInformation("Connection from: {@RemoteEndpoint}", this.Socket.RemoteEndPoint?.ToString());
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
}
private static byte[] Decrypt(byte[] buffer)
{
for (var i = 0; i < buffer.Length; ++i)
{
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
}
return buffer;
}
}

67
Server/ChannelSession.cs Normal file
View file

@ -0,0 +1,67 @@
namespace Server;
using System.Security.Cryptography;
using System.Text;
using MassTransit.Mediator;
using Microsoft.Extensions.Logging;
using NetCoreServer;
public class ChannelSession : TcpSession
{
private static readonly byte[] Key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 }
.Reverse().ToArray();
private static readonly byte[] Iv = new byte[]
{
0xfe, 220, 0xba, 0x98, 0x76, 0x54, 50, 0x10, 15, 30, 0x2d, 60, 0x4b, 90, 0x69, 120
}.Reverse().ToArray();
private readonly ICryptoTransform decryptor;
private readonly ICryptoTransform encryptor;
private readonly ILogger<ChannelSession> logger;
private readonly IMediator mediator;
public ChannelSession(TcpServer server, IMediator mediator, ILogger<ChannelSession> logger) : base(server)
{
this.mediator = mediator;
this.logger = logger;
var aes = Aes.Create();
aes.Key = Key;
aes.IV = Iv;
aes.Padding = PaddingMode.None;
aes.Mode = CipherMode.ECB;
this.decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
this.encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
}
protected override void OnReceived(byte[] buffer, long offset, long size)
{
try
{
using (var ms = new MemoryStream(Decrypt(buffer)))
using (var cs = new CryptoStream(ms, this.decryptor, CryptoStreamMode.Read))
{
cs.Read(buffer);
}
base.OnReceived(buffer, offset, size);
}
catch (CryptographicException ex)
{
this.logger.LogError("An error has occured while decrypting: {ErrorMessage}", ex.Message);
this.logger.LogError("Default buffer message: {Message}", Encoding.ASCII.GetString(buffer));
}
}
private static byte[] Decrypt(byte[] buffer)
{
for (var i = 0; i < buffer.Length; ++i)
{
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
}
return buffer;
}
}

View file

@ -0,0 +1,18 @@
namespace Server.Consumers;
using MassTransit;
using Packets;
using Services;
public class PacketConsumer : IConsumer<RawPacket>
{
private readonly PacketDistributorService distributorService;
public PacketConsumer(PacketDistributorService distributorService) => this.distributorService = distributorService;
public Task Consume(ConsumeContext<RawPacket> context)
{
this.distributorService.AddPacket(context.Message);
return Task.CompletedTask;
}
}

View file

@ -0,0 +1,23 @@
namespace Server.DB.Documents;
using Microsoft.EntityFrameworkCore;
public class Account
{
public Guid Id { get; set; }
public Account(string username, byte[] password, string email, byte permissionLevel, byte[] salt)
{
this.Username = username;
this.Password = password;
this.Email = email;
this.PermissionLevel = permissionLevel;
this.Salt = salt;
}
public string Username { get; set; }
public byte[] Password { get; set; }
public string Email { get; set; }
public byte PermissionLevel { get; set; }
public byte[] Salt { get; set; }
}

View file

@ -1,6 +1,5 @@
// <auto-generated /> // <auto-generated />
using System; using System;
using Continuity.AuthServer.DB;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
@ -26,7 +25,7 @@ namespace Server.DB.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Continuity.AuthServer.DB.Documents.Account", b => modelBuilder.Entity("Server.DB.Documents.Account", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()

View file

@ -0,0 +1,38 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Accounts",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Username = table.Column<string>(type: "varchar(20)", nullable: false),
Password = table.Column<byte[]>(type: "bytea", nullable: false),
Email = table.Column<string>(type: "text", nullable: false),
PermissionLevel = table.Column<byte>(type: "smallint", nullable: false),
Salt = table.Column<byte[]>(type: "bytea", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Accounts", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Accounts");
}
}
}

View file

@ -0,0 +1,57 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Server.DB;
#nullable disable
namespace Server.DB.Migrations
{
[DbContext(typeof(WonderkingContext))]
partial class WonderkingContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Server.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<byte[]>("Password")
.IsRequired()
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.IsRequired()
.HasColumnType("bytea");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.ToTable("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,37 @@
namespace Server.DB;
using System.Data.Common;
using Documents;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Npgsql;
public class WonderkingContext : DbContext
{
private readonly ILoggerFactory loggerFactory;
private readonly IConfiguration configuration;
public WonderkingContext(ILoggerFactory loggerFactory, IConfiguration configuration)
{
this.loggerFactory = loggerFactory;
this.configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
optionsBuilder
.UseNpgsql(
$"Host={this.configuration["DB:Host"]};Username={this.configuration["DB:Username"]};Password={this.configuration["DB:Password"]};Database={this.configuration["DB:Database"]};Port={this.configuration["DB:Port"]}")
.EnableSensitiveDataLogging().UseLoggerFactory(this.loggerFactory);
protected override void OnModelCreating(ModelBuilder modelBuilder) =>
modelBuilder.Entity<Account>(builder =>
{
builder.Property(b => b.Username).HasColumnType("varchar(20)");
builder.Property(b => b.Password).HasColumnType("bytea");
builder.Property(b => b.Salt).HasColumnType("bytea");
builder.HasKey(b => b.Id);
});
public DbSet<Account> Accounts { get; set; }
}

18
Server/Dockerfile Normal file
View file

@ -0,0 +1,18 @@
FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:7.0.400 AS build
WORKDIR /src
COPY ["Server/Server.csproj", "Server/"]
RUN dotnet restore "Server/Server.csproj"
COPY . .
WORKDIR "/src/Server"
RUN dotnet build "Server.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Server.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Server.dll"]

View file

@ -0,0 +1,12 @@
namespace Server.PacketHandlers;
using JetBrains.Annotations;
using NetCoreServer;
using Packets;
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public interface IPacketHandler<in T> where T : IPacket
{
[UsedImplicitly]
public Task HandleAsync(T packet, TcpSession session);
}

View file

@ -0,0 +1,82 @@
namespace Server.PacketHandlers;
using System.Security.Cryptography;
using System.Text;
using DB;
using DB.Documents;
using Konscious.Security.Cryptography;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NetCoreServer;
using Packets.Incoming;
using Packets.Outgoing;
public class LoginHandler : IPacketHandler<LoginInfoPacket>
{
private readonly IConfiguration configuration;
private readonly ILogger<LoginHandler> logger;
private readonly WonderkingContext wonderkingContext;
public LoginHandler(ILogger<LoginHandler> logger, WonderkingContext wonderkingContext, IConfiguration configuration)
{
this.logger = logger;
this.wonderkingContext = wonderkingContext;
this.configuration = configuration;
}
public async Task HandleAsync(LoginInfoPacket packet, TcpSession session)
{
var loginResponseReason = LoginResponseReason.Error;
this.logger.LogInformation("Login data: Username {Username} & Password {Password}", packet.Username,
packet.Password);
var account = this.wonderkingContext.Accounts.FirstOrDefault(a => a.Username == packet.Username);
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id
// "Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism."
var argon2Id = new Argon2id(Encoding.ASCII.GetBytes(packet.Password));
argon2Id.MemorySize = 1024 * 40;
argon2Id.Iterations = 4;
argon2Id.DegreeOfParallelism = 2;
if (account == null)
{
if (this.configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin"))
{
argon2Id.Salt = RandomNumberGenerator.GetBytes(128);
var finalAccount =
await this.wonderkingContext.Accounts.AddAsync(new Account(packet.Username, Array.Empty<byte>(), "",
0, argon2Id.Salt));
await this.wonderkingContext.SaveChangesAsync();
argon2Id.AssociatedData = finalAccount.Entity.Id.ToByteArray();
finalAccount.Entity.Password = await argon2Id.GetBytesAsync(128);
this.wonderkingContext.Accounts.Update(finalAccount.Entity);
loginResponseReason = LoginResponseReason.Ok;
await this.wonderkingContext.SaveChangesAsync();
}
else
{
// TODO: Send Message that account does not exist
this.logger.LogInformation("Requested account for user: {Username} does not exist", packet.Username);
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
}
}
else
{
argon2Id.Salt = account.Salt;
argon2Id.AssociatedData = account.Id.ToByteArray();
var tempPasswordBytes = await argon2Id.GetBytesAsync(128);
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
? LoginResponseReason.Ok
: LoginResponseReason.WrongPassword;
}
var loginResponsePacket = new LoginResponsePacket
{
ResponseReason = loginResponseReason,
ChannelData = new[] { new ServerChannelData { ChannelId = 0, LoadPercentage = 75, ServerId = 0 } },
UnknownFlag = 1,
IsGameMaster = true
};
var sess = session as AuthSession;
sess.Send(loginResponsePacket);
}
}

View file

@ -1,9 +1,7 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. namespace Server.Packets;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Wonderking.Packets;
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public interface IPacket public interface IPacket
{ {

View file

@ -0,0 +1,35 @@
namespace Server.Packets.Incoming;
using System.Text;
[PacketId(OperationCode.LoginInfo)]
public class LoginInfoPacket : IPacket
{
public required string Username { get; set; }
public required string Password { get; set; }
public void Deserialize(byte[] data)
{
this.Username = Encoding.ASCII.GetString(data, 0, 20).TrimEnd('\0');
this.Password = Encoding.ASCII.GetString(data, 20, 31).TrimEnd('\0');
}
public byte[] Serialize()
{
Span<byte> dataSpan = stackalloc byte[20 + 31];
var usernameBytes = Encoding.ASCII.GetBytes(this.Username);
var passwordBytes = Encoding.ASCII.GetBytes(this.Password);
for (var i = 0; i < 20 || i < this.Username.Length; i++)
{
dataSpan[i] = usernameBytes[i];
}
for (var i = 0; i < 31 || i < this.Password.Length; i++)
{
dataSpan[20 + i] = passwordBytes[i];
}
return dataSpan.ToArray();
}
}

View file

@ -0,0 +1,7 @@
namespace Server.Packets;
public enum OperationCode : ushort
{
LoginInfo = 11,
LoginResponse = 12
}

View file

@ -0,0 +1,52 @@
namespace Server.Packets.Outgoing;
[PacketId(OperationCode.LoginResponse)]
public class LoginResponsePacket : IPacket
{
public required LoginResponseReason ResponseReason { get; set; }
public required byte UnknownFlag { get; set; } = 1;
public required bool IsGameMaster { get; set; }
public required ServerChannelData[] ChannelData { get; set; }
public void Deserialize(byte[] data)
{
this.ResponseReason = (LoginResponseReason)data[0];
this.UnknownFlag = data[1];
this.IsGameMaster = BitConverter.ToBoolean(data, 2);
var channelAmount = BitConverter.ToUInt16(data, 3);
const int sizeOfServerChannelData = 5;
this.ChannelData = Enumerable.Repeat(0, channelAmount).Select(i => new ServerChannelData
{
ServerId = BitConverter.ToUInt16(data, 5 + 0 + (i * sizeOfServerChannelData)),
ChannelId = BitConverter.ToUInt16(data, 5 + 2 + (i * sizeOfServerChannelData)),
LoadPercentage = data[5 + 4 + (i * sizeOfServerChannelData)]
}).ToArray();
}
public byte[] Serialize()
{
const int sizeOfServerChannelData = 5;
Span<byte> dataSpan = stackalloc byte[5 + (this.ChannelData.Length * sizeOfServerChannelData)];
dataSpan.Clear();
dataSpan[0] = (byte)this.ResponseReason;
dataSpan[1] = this.UnknownFlag;
dataSpan[2] = BitConverter.GetBytes(this.IsGameMaster)[0];
var bytesOfChannelAmount = BitConverter.GetBytes((ushort)this.ChannelData.Length);
dataSpan[3] = bytesOfChannelAmount[0];
dataSpan[4] = bytesOfChannelAmount[1];
for (var i = 0; i < this.ChannelData.Length; i++)
{
var bytesOfServerId = BitConverter.GetBytes(this.ChannelData[i].ServerId);
var bytesOfChannelId = BitConverter.GetBytes(this.ChannelData[i].ChannelId);
dataSpan[5 + 0 + (i * sizeOfServerChannelData)] = bytesOfServerId[0];
dataSpan[5 + 1 + (i * sizeOfServerChannelData)] = bytesOfServerId[1];
dataSpan[5 + 2 + (i * sizeOfServerChannelData)] = bytesOfChannelId[0];
dataSpan[5 + 3 + (i * sizeOfServerChannelData)] = bytesOfChannelId[1];
dataSpan[5 + 4 + (i * sizeOfServerChannelData)] = this.ChannelData[i].LoadPercentage;
}
return dataSpan.ToArray();
}
}

View file

@ -1,6 +1,4 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. namespace Server.Packets.Outgoing;
namespace Wonderking.Packets.Outgoing.Data;
public enum LoginResponseReason : byte public enum LoginResponseReason : byte
{ {
@ -18,8 +16,8 @@ public enum LoginResponseReason : byte
LockedDuePayment, LockedDuePayment,
UserDeletedBigpoint, UserDeletedBigpoint,
NoMoreTries, NoMoreTries,
XmlError12, XMLError12,
XmlRpcError, XMLRPCError,
FileLoadFail, // arbitrary file load error (maybe we're able to load custom files) FileLoadFail, // arbitrary file load error (maybe we're able to load custom files)
ThisIsNotAServiceArea, ThisIsNotAServiceArea,
None None

View file

@ -0,0 +1,8 @@
namespace Server.Packets.Outgoing;
public struct ServerChannelData
{
public ushort ServerId { get; set; }
public ushort ChannelId { get; set; }
public byte LoadPercentage { get; set; }
}

View file

@ -0,0 +1,8 @@
namespace Server.Packets;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class PacketIdAttribute : Attribute
{
public PacketIdAttribute(OperationCode code) => this.Code = code;
public OperationCode Code { get; }
}

View file

@ -1,29 +1,26 @@
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. namespace Server.Packets;
using MassTransit; using MassTransit;
using Wonderking.Packets;
namespace Continuity.AuthServer.Packets;
[MessageUrn("packets")] [MessageUrn("packets")]
public class RawPacket public class RawPacket
{ {
public RawPacket(OperationCode operationCode, Span<byte> messageBody, uint aliveTime, byte unknownValue2, public RawPacket(OperationCode operationCode, byte[] messageBody, uint aliveTime, byte unknownValue2,
byte unknownValue, Guid sessionId, AuthSession session) byte unknownValue, Guid sessionId, AuthSession session)
{ {
MessageBody = messageBody.ToArray(); this.MessageBody = messageBody;
UnknownValue2 = unknownValue2; this.UnknownValue2 = unknownValue2;
UnknownValue = unknownValue; this.UnknownValue = unknownValue;
SessionId = sessionId; this.SessionId = sessionId;
Session = session; this.Session = session;
OperationCode = operationCode; this.OperationCode = operationCode;
/* /*
* 20s = 5 * 20s = 5
* 15s = 4 * 15s = 4
* 10s = 3 * 10s = 3
* client alive time * 5s => uptime * client alive time * 5s => uptime
*/ */
ClientAliveTime = TimeSpan.FromSeconds(5 * aliveTime); this.ClientAliveTime = TimeSpan.FromSeconds(5 * aliveTime);
} }
public OperationCode OperationCode { get; } public OperationCode OperationCode { get; }

41
Server/Program.cs Normal file
View file

@ -0,0 +1,41 @@
#pragma warning disable AV1500
using System.Net;
using System.Reflection;
using MassTransit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Server.DB;
using Server.Services;
var builder = Host.CreateApplicationBuilder();
var configurationRoot = builder.Configuration.AddJsonFile("settings.json", false, true)
.AddEnvironmentVariables().Build();
builder.Services.AddLogging();
builder.Logging.AddFile("Logs/Server-{Date}.log", LogLevel.Debug);
builder.Logging.AddFile("Logs/Server-{Date}.json.log", LogLevel.Debug, isJson: true);
builder.Services.AddEntityFrameworkNpgsql();
builder.Services.AddDbContext<WonderkingContext>();
builder.Services.AddSingleton<PacketDistributorService>();
builder.Services.AddHostedService<PacketDistributorService>(provider =>
provider.GetService<PacketDistributorService>() ?? throw new InvalidOperationException());
builder.Services.AddMassTransit(x =>
{
x.UsingInMemory((context, configurator) => configurator.ConfigureEndpoints(context));
x.AddMediator(cfg => cfg.AddConsumers(Assembly.GetExecutingAssembly()));
});
builder.Services.AddHostedService<WonderkingAuthServer>(provider => new WonderkingAuthServer(IPAddress.Any, 10001,
provider.GetService<ILogger<WonderkingAuthServer>>() ?? throw new InvalidOperationException(),
provider.GetService<IServiceProvider>() ?? throw new InvalidOperationException()));
using var host = builder.Build();
await using (var scope = host.Services.CreateAsyncScope())
{
var db = scope.ServiceProvider.GetRequiredService<WonderkingContext>();
await db.Database.MigrateAsync();
}
await host.RunAsync();
#pragma warning restore AV1500

87
Server/Server.csproj Normal file
View file

@ -0,0 +1,87 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<RootNamespace>Server</RootNamespace>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
<Content Include="..\.dockerignore">
<Link>.dockerignore</Link>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DotNext" Version="4.13.1" />
<PackageReference Include="DotNext.IO" Version="4.13.1" />
<PackageReference Include="DotNext.Metaprogramming" Version="4.13.1" />
<PackageReference Include="DotNext.Reflection" Version="4.9.0" />
<PackageReference Include="DotNext.Threading" Version="4.13.1" />
<PackageReference Include="DotNext.Unsafe" Version="4.13.1" />
<PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="JetBrains.Annotations" Version="2023.2.0"/>
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0" />
<PackageReference Include="MassTransit" Version="8.0.16"/>
<PackageReference Include="MassTransit.Analyzers" Version="8.0.16">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1"/>
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0"/>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.7.30">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NetCoreServer" Version="7.0.0"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.10.4539">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Puma.Security.Rules.2022" Version="2.4.23">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Formatting.Analyzers" Version="4.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0"/>
</ItemGroup>
<ItemGroup>
<None Update="settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -0,0 +1,139 @@
namespace Server.Services;
using System.Collections.Concurrent;
using System.Reflection;
using MassTransit.Internals;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
using PacketHandlers;
using Packets;
using static DotNext.Metaprogramming.CodeGenerator;
using static DotNext.Linq.Expressions.ExpressionBuilder;
public class PacketDistributorService : IHostedService
{
private readonly ConcurrentQueue<RawPacket> concurrentQueue;
private readonly ILogger<PacketDistributorService> logger;
private readonly Dictionary<OperationCode, Type> packetHandlers;
private readonly Dictionary<OperationCode, Func<byte[], IPacket>> deserializationMap;
private readonly IServiceProvider serviceProvider;
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
{
this.concurrentQueue = new ConcurrentQueue<RawPacket>();
this.logger = logger;
this.serviceProvider = serviceProvider;
this.packetHandlers = new Dictionary<OperationCode, Type>();
this.deserializationMap = new Dictionary<OperationCode, Func<byte[], IPacket>>();
var executingAssembly = Assembly.GetExecutingAssembly();
var packetsTypes = this.GetPacketsWithId(executingAssembly);
this.packetHandlers = this.GetAllPacketHandlersWithId(executingAssembly);
foreach (var packetsType in packetsTypes)
{
var lambda = Lambda<Func<byte[], IPacket>>(fun =>
{
var arg = fun[0];
var newPacket = packetsType.Value.New();
var packetVariable = DeclareVariable(packetsType.Value, "packet");
Assign(packetVariable, newPacket);
Call(packetVariable, nameof(IPacket.Deserialize), arg);
Return(packetVariable);
}).Compile();
logger.LogInformation("Packet creation function created for {Opcode}", packetsType.Key);
this.deserializationMap.Add(packetsType.Key, lambda);
}
}
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
private Dictionary<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
{
var packetsWithId = executingAssembly.GetTypes().AsParallel()
.Where(type => type.GetCustomAttribute<PacketIdAttribute>() != null && type.HasInterface(typeof(IPacket)) &&
!type.IsInterface)
.ToDictionary(packet => packet.GetCustomAttribute<PacketIdAttribute>()!.Code);
if (packetsWithId is not { Count: 0 })
{
packetsWithId.AsParallel().ForAll(packet =>
{
this.logger.LogTrace("Packet with ID: {PacketID} has been added as {PacketName}", packet.Key,
packet.Value.FullName);
});
return packetsWithId;
}
this.logger.LogCritical("No Packets have been found");
throw new IncompleteInitialization();
}
private Dictionary<OperationCode, Type> GetAllPacketHandlersWithId(Assembly assembly)
{
var packetHandlersWithId = assembly.GetTypes().AsParallel().Where(t =>
t is { IsClass: true, IsAbstract: false } && t
.GetInterfaces().Any(i =>
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketHandler<>))).ToDictionary(type =>
type.GetInterfaces().First(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IPacketHandler<>))
.GetGenericArguments()[0].GetCustomAttribute<PacketIdAttribute>().Code);
if (packetHandlersWithId is not { Count: 0 })
{
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
{
this.logger.LogTrace("PacketHandler with ID: {PacketID} has been added as {PacketName}",
packetHandler.Key,
packetHandler.Value.FullName);
});
return packetHandlersWithId;
}
this.logger.LogCritical("No PacketHandlers have been found");
throw new IncompleteInitialization();
}
public void AddPacket(RawPacket rawPacket)
{
this.concurrentQueue.Enqueue(rawPacket);
this.DequeueRawPacket();
this.logger.LogInformation("Packet with ID: {MessageOperationCode} has been received",
rawPacket.OperationCode);
}
private void DequeueRawPacket()
{
if (this.concurrentQueue.TryDequeue(out var item))
{
ThreadPool.QueueUserWorkItem(this.InvokePacketHandler, item, true);
}
}
private void InvokePacketHandler(RawPacket item)
{
this.logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",
item.Session.Id, item.OperationCode);
if (!this.deserializationMap.ContainsKey(item.OperationCode))
{
this.logger.LogInformation("Couldn't find Packet type for Id: {Opcode}", item.OperationCode);
return;
}
var packet = this.deserializationMap[item.OperationCode](item.MessageBody);
var packetHandler =
ActivatorUtilities.GetServiceOrCreateInstance(this.serviceProvider,
this.packetHandlers[item.OperationCode]);
packetHandler.GetType().GetMethod("HandleAsync")
?.Invoke(packetHandler, new object[] { packet, item.Session });
this.logger.LogDebug("Packet data {PacketData}", JsonConvert.SerializeObject(packet));
this.logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} has finished",
item.Session.Id,
item.OperationCode);
}
}

View file

@ -0,0 +1,62 @@
namespace Server.Services;
using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NetCoreServer;
public class WonderkingAuthServer : TcpServer, IHostedService
{
private readonly ILogger<WonderkingAuthServer> logger;
private readonly IServiceProvider serviceProvider;
public WonderkingAuthServer(IPAddress address, int port, ILogger<WonderkingAuthServer> logger,
IServiceProvider serviceProvider) : base(address, port)
{
this.logger = logger;
this.serviceProvider = serviceProvider;
}
public Task StartAsync(CancellationToken cancellationToken)
{
this.Start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
this.Stop();
return Task.CompletedTask;
}
protected override TcpSession CreateSession() =>
ActivatorUtilities.CreateInstance<AuthSession>(this.serviceProvider, this);
protected override void OnStarting()
{
this.logger.LogInformation("Starting");
base.OnStarting();
}
protected override void OnStarted()
{
this.logger.LogInformation("Started");
base.OnStarted();
}
protected override void OnStopping()
{
this.logger.LogInformation("Stopping");
base.OnStopping();
}
protected override void OnStopped()
{
this.logger.LogInformation("Stopped");
base.OnStopped();
}
protected override void OnError(SocketError error) => this.logger.LogError("An error has occured {Error}", error);
}

12
Server/settings.json Normal file
View file

@ -0,0 +1,12 @@
{
"DB": {
"Username": "continuitydevuser",
"Host": "perf.rainote.dev",
"Password": "7>CU`D2/LKw6hD/7",
"Database": "continuity",
"Port": "13543"
},
"Testing": {
"CreateAccountOnLogin": true
}
}

View file

@ -1,2 +0,0 @@
FROM nginx:1.25.3-alpine3.18-slim
COPY .public /usr/share/nginx/html

View file

@ -1,20 +0,0 @@
# Character Creation Packet
## Metadata
**Operation Code**: 15
### Structure
| Identifier | Datatype | Size in bytes |
|------------|----------|---------------|
| Slot | byte | 1 |
| Unknown | byte | 1 |
| Id | ushort | 2 |
| Name | string | 20 |
| First Job | byte | 1 |
| Gender | byte | 1 |
| Hair | byte | 1 |
| Eyes | byte | 1 |
| Shirt | byte | 1 |
| Pants | byte | 1 |

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