diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d72312d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,239 @@ +root = true + +############################### +# Core EditorConfig Options # +############################### + +[*] +charset = utf-8 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +############################### +# C# Coding Conventions # +############################### + +[*.cs] +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = false +csharp_indent_labels = flush_left +csharp_indent_switch_labels = true + +csharp_new_line_before_catch = false +csharp_new_line_before_else = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_anonymous_types = false +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_open_brace = none +csharp_new_line_between_query_expression_clauses = false + +csharp_prefer_braces = true:warning +csharp_prefer_simple_default_expression = true:warning +csharp_prefer_simple_using_statement = true:warning +csharp_prefer_static_local_function = true:warning + +csharp_preferred_modifier_order = public, protected, internal, private, file, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, required, volatile, async:warning + +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false + +csharp_space_after_cast = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_square_brackets = false + +csharp_style_conditional_delegate_call = true:warning +csharp_style_deconstructed_variable_declaration = true:warning + +csharp_style_expression_bodied_accessors = true:warning +csharp_style_expression_bodied_constructors = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_lambdas = true:warning +csharp_style_expression_bodied_local_functions = true:warning +csharp_style_expression_bodied_methods = true:warning +csharp_style_expression_bodied_operators = true:warning +csharp_style_expression_bodied_properties = true:warning + +csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +csharp_style_inlined_variable_declaration = true:warning + +csharp_style_namespace_declarations = file_scoped:warning + +csharp_style_pattern_matching_over_as_with_null_check = true:warning +csharp_style_pattern_matching_over_is_with_cast_check = true:warning + +csharp_style_prefer_extended_property_pattern = true:warning +dotnet_style_prefer_foreach_explicit_cast_in_source = always:warning +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_local_over_anonymous_function = true:warning +csharp_style_prefer_method_group_conversion = true:warning +csharp_style_prefer_not_pattern = true:warning +csharp_style_prefer_null_check_over_type_check = true:warning +csharp_style_prefer_pattern_matching = true:warning +csharp_style_prefer_primary_constructors = true:warning +csharp_style_prefer_range_operator = true:warning +csharp_style_prefer_readonly_struct = true:warning +csharp_style_prefer_readonly_struct_member = true:warning +csharp_style_prefer_switch_expression = true:warning +csharp_style_prefer_top_level_statements = false:warning +csharp_style_prefer_tuple_swap = true:warning +csharp_style_prefer_utf8_string_literals = true:warning + +csharp_style_throw_expression = true:warning + +csharp_style_unused_value_assignment_preference = discard_variable:warning +csharp_style_unused_value_expression_statement_preference = discard_variable:warning + +csharp_style_var_elsewhere = false:warning +csharp_style_var_for_built_in_types = false:warning +csharp_style_var_when_type_is_apparent = false:warning + +csharp_using_directive_placement = outside_namespace:warning + +############################### +# .NET Coding Conventions # +############################### + +dotnet_analyzer_diagnostic.severity = warning + +dotnet_code_quality.ca3003.excluded_symbol_names = BotController +dotnet_code_quality.ca3012.excluded_symbol_names = BotController|CommandController + +dotnet_code_quality_unused_parameters = all:warning + +dotnet_diagnostic.ca1028.severity = silent +dotnet_diagnostic.ca1031.severity = silent +dotnet_diagnostic.ca1863.severity = silent + +# Rule - almost everything +dotnet_naming_rule.almost_everything_must_be_pascal_case.severity = warning +dotnet_naming_rule.almost_everything_must_be_pascal_case.style = pascal_case +dotnet_naming_rule.almost_everything_must_be_pascal_case.symbols = almost_everything + +# Rule - enums +dotnet_naming_rule.enums_must_be_e_pascal_case.severity = warning +dotnet_naming_rule.enums_must_be_e_pascal_case.style = e_pascal_case +dotnet_naming_rule.enums_must_be_e_pascal_case.symbols = enums + +# Rule - interfaces +dotnet_naming_rule.interfaces_must_be_i_pascal_case.severity = warning +dotnet_naming_rule.interfaces_must_be_i_pascal_case.style = i_pascal_case +dotnet_naming_rule.interfaces_must_be_i_pascal_case.symbols = interfaces + +# Rule - local parameters +dotnet_naming_rule.local_parameters_must_be_camel_case.severity = warning +dotnet_naming_rule.local_parameters_must_be_camel_case.style = camel_case +dotnet_naming_rule.local_parameters_must_be_camel_case.symbols = local_parameters + +# Rule - type parameters +dotnet_naming_rule.type_parameters_must_be_t_pascal_case.severity = warning +dotnet_naming_rule.type_parameters_must_be_t_pascal_case.style = t_pascal_case +dotnet_naming_rule.type_parameters_must_be_t_pascal_case.symbols = type_parameters + +# Style - camelCase +dotnet_naming_style.camel_case.capitalization = camel_case + +# Style - EPascalCase +dotnet_naming_style.e_pascal_case.capitalization = pascal_case +dotnet_naming_style.e_pascal_case.required_prefix = E + +# Style - IPascalCase +dotnet_naming_style.i_pascal_case.capitalization = pascal_case +dotnet_naming_style.i_pascal_case.required_prefix = I + +# Style - PascalCase +dotnet_naming_style.pascal_case.capitalization = pascal_case + +# Style - TPascalCase +dotnet_naming_style.t_pascal_case.capitalization = pascal_case +dotnet_naming_style.t_pascal_case.required_prefix = T + +# Symbol - almost everything +dotnet_naming_symbols.almost_everything.applicable_accessibilities = * +dotnet_naming_symbols.almost_everything.applicable_kinds = namespace, class, struct, property, method, field, event, delegate + +# Symbol - enums +dotnet_naming_symbols.enums.applicable_accessibilities = * +dotnet_naming_symbols.enums.applicable_kinds = enum + +# Symbol - interfaces +dotnet_naming_symbols.interfaces.applicable_accessibilities = * +dotnet_naming_symbols.interfaces.applicable_kinds = interface + +# Symbol - local parameters +dotnet_naming_symbols.local_parameters.applicable_accessibilities = * +dotnet_naming_symbols.local_parameters.applicable_kinds = parameter, local, local_function + +# Symbol - type parameters +dotnet_naming_symbols.type_parameters.applicable_accessibilities = * +dotnet_naming_symbols.type_parameters.applicable_kinds = type_parameter + +dotnet_remove_unnecessary_suppression_exclusions = none:warning +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true + +dotnet_style_coalesce_expression = true:warning +dotnet_style_collection_initializer = true:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_namespace_match_folder = true:warning +dotnet_style_null_propagation = true:warning +dotnet_style_object_initializer = true:warning + +dotnet_style_parentheses_in_arithmetic_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 +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning + +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning + +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_compound_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_return = true:warning +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_simplified_boolean_expressions = true:warning +dotnet_style_prefer_simplified_interpolation = true:warning + +dotnet_style_qualification_for_event = false:warning +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_property = false:warning + +dotnet_style_readonly_field = true:warning +dotnet_style_require_accessibility_modifiers = always:warning + +############################### +# JetBrains, IntelliJ/Rider # +############################### + +[*.{csproj,props,resx,xml}] +ij_xml_keep_blank_lines = 1 +ij_xml_keep_line_breaks = false +ij_xml_keep_line_breaks_in_text = false +ij_xml_space_inside_empty_tag = true + +[*.{json,json5}] +ij_json_keep_line_breaks = false diff --git a/ItemDispenser.sln.DotSettings b/ItemDispenser.sln.DotSettings new file mode 100644 index 0000000..aa02323 --- /dev/null +++ b/ItemDispenser.sln.DotSettings @@ -0,0 +1,807 @@ + + True + True + FullFormat + True + False + True + True + + SOLUTION + True + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + HINT + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + HINT + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + HINT + HINT + SUGGESTION + WARNING + + SUGGESTION + SUGGESTION + HINT + WARNING + SUGGESTION + + True + SUGGESTION + WARNING + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + HINT + HINT + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + + + WARNING + WARNING + WARNING + SUGGESTION + SUGGESTION + WARNING + WARNING + WARNING + HINT + HINT + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + HINT + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + WARNING + DO_NOT_SHOW + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + + + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + WARNING + SUGGESTION + WARNING + SUGGESTION + WARNING + HINT + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + HINT + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + + True + WARNING + WARNING + + + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + WARNING + WARNING + WARNING + True + SUGGESTION + Default + Default + Default + + <?xml version="1.0" encoding="utf-16"?><Profile name="Archi"><CSReorderTypeMembers>True</CSReorderTypeMembers><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><HtmlReformatCode>True</HtmlReformatCode><JsInsertSemicolon>True</JsInsertSemicolon><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CorrectVariableKindsDescriptor>True</CorrectVariableKindsDescriptor><VariablesToInnerScopesDescriptor>True</VariablesToInnerScopesDescriptor><StringToTemplatesDescriptor>True</StringToTemplatesDescriptor><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><RemoveRedundantQualifiersTs>True</RemoveRedundantQualifiersTs><OptimizeImportsTs>True</OptimizeImportsTs><OptimizeReferenceCommentsTs>True</OptimizeReferenceCommentsTs><PublicModifierStyleTs>True</PublicModifierStyleTs><ExplicitAnyTs>True</ExplicitAnyTs><TypeAnnotationStyleTs>True</TypeAnnotationStyleTs><RelativePathStyleTs>True</RelativePathStyleTs><AsInsteadOfCastTs>True</AsInsteadOfCastTs><XMLReformatCode>True</XMLReformatCode><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="True" ArrangeVarStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" /><RemoveCodeRedundanciesVB>True</RemoveCodeRedundanciesVB><CssAlphabetizeProperties>True</CssAlphabetizeProperties><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CssReformatCode>True</CssReformatCode><VBReformatCode>True</VBReformatCode><VBFormatDocComments>True</VBFormatDocComments><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><CSUpdateFileHeader>True</CSUpdateFileHeader><Xaml.RedundantFreezeAttribute>True</Xaml.RedundantFreezeAttribute><Xaml.RemoveRedundantModifiersAttribute>True</Xaml.RemoveRedundantModifiersAttribute><Xaml.RemoveRedundantNameAttribute>True</Xaml.RemoveRedundantNameAttribute><Xaml.RemoveRedundantResource>True</Xaml.RemoveRedundantResource><Xaml.RemoveRedundantCollectionProperty>True</Xaml.RemoveRedundantCollectionProperty><Xaml.RemoveRedundantAttachedPropertySetter>True</Xaml.RemoveRedundantAttachedPropertySetter><Xaml.RemoveRedundantStyledValue>True</Xaml.RemoveRedundantStyledValue><Xaml.RemoveRedundantNamespaceAlias>True</Xaml.RemoveRedundantNamespaceAlias><Xaml.RemoveForbiddenResourceName>True</Xaml.RemoveForbiddenResourceName><Xaml.RemoveRedundantGridDefinitionsAttribute>True</Xaml.RemoveRedundantGridDefinitionsAttribute><Xaml.RemoveRedundantGridSpanAttribut>True</Xaml.RemoveRedundantGridSpanAttribut><Xaml.RemoveRedundantUpdateSourceTriggerAttribute>True</Xaml.RemoveRedundantUpdateSourceTriggerAttribute><Xaml.RemoveRedundantBindingModeAttribute>True</Xaml.RemoveRedundantBindingModeAttribute><CppAddTypenameTemplateKeywords>True</CppAddTypenameTemplateKeywords><CppJoinDeclarationAndAssignmentDescriptor>True</CppJoinDeclarationAndAssignmentDescriptor><CppMakeLocalVarConstDescriptor>True</CppMakeLocalVarConstDescriptor><CppMakeMethodConst>True</CppMakeMethodConst><CppMakeMethodStatic>True</CppMakeMethodStatic><CppRemoveElseKeyword>True</CppRemoveElseKeyword><CppRemoveRedundantMemberInitializerDescriptor>True</CppRemoveRedundantMemberInitializerDescriptor><CppRemoveRedundantParentheses>True</CppRemoveRedundantParentheses><CppShortenQualifiedName>True</CppShortenQualifiedName><CppDeleteRedundantSpecifier>True</CppDeleteRedundantSpecifier><CppRemoveStatement>True</CppRemoveStatement><CppRemoveTemplateArgumentsDescriptor>True</CppRemoveTemplateArgumentsDescriptor><CppDeleteRedundantTypenameTemplateKeywords>True</CppDeleteRedundantTypenameTemplateKeywords><CppRemoveUnreachableCode>True</CppRemoveUnreachableCode><CppRemoveUnusedIncludes>True</CppRemoveUnusedIncludes><CppRemoveUnusedLambdaCaptures>True</CppRemoveUnusedLambdaCaptures><CppCStyleToStaticCastDescriptor>True</CppCStyleToStaticCastDescriptor><CppReplaceExpressionWithBooleanConst>True</CppReplaceExpressionWithBooleanConst><CppMakeIfConstexpr>True</CppMakeIfConstexpr><CppMakePostfixOperatorPrefix>True</CppMakePostfixOperatorPrefix><CppChangeSmartPointerToMakeFunction>True</CppChangeSmartPointerToMakeFunction><CppReplaceThrowWithRethrowFix>True</CppReplaceThrowWithRethrowFix><CppReplaceExpressionWithNullptr>True</CppReplaceExpressionWithNullptr><CppCodeStyleCleanupDescriptor ArrangeAuto="True" ArrangeBraces="True" ArrangeCVQualifiers="True" ArrangeFunctionDeclarations="True" ArrangeNestedNamespaces="True" ArrangeOverridingFunctions="True" ArrangeSlashesInIncludeDirectives="True" ArrangeTypeAliases="True" SortIncludeDirectives="True" SortMemberInitializers="True" /><CppReformatCode>True</CppReformatCode><CppUpdateFileHeader>True</CppUpdateFileHeader><IDEA_SETTINGS>&lt;profile version="1.0"&gt; + &lt;option name="myName" value="Archi" /&gt; + &lt;inspection_tool class="ConditionalExpressionWithIdenticalBranchesJS" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="ES6ShorthandObjectProperty" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="JSArrowFunctionBracesCanBeRemoved" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="JSRemoveUnnecessaryParentheses" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="TypeScriptExplicitMemberType" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="UnterminatedStatementJS" enabled="true" level="WARNING" enabled_by_default="true" /&gt; +&lt;/profile&gt;</IDEA_SETTINGS><ShaderLabReformatCode>True</ShaderLabReformatCode><CppRemoveCastDescriptor>True</CppRemoveCastDescriptor><CppRemoveElaboratedTypeSpecifierDescriptor>True</CppRemoveElaboratedTypeSpecifierDescriptor><CppRemoveRedundantLambdaParameterListDescriptor>True</CppRemoveRedundantLambdaParameterListDescriptor><CppTypeTraitAliasDescriptor>True</CppTypeTraitAliasDescriptor><CppReplaceTieWithStructuredBindingDescriptor>True</CppReplaceTieWithStructuredBindingDescriptor><CppUseAssociativeContainsDescriptor>True</CppUseAssociativeContainsDescriptor><CppUseEraseAlgorithmDescriptor>True</CppUseEraseAlgorithmDescriptor><RIDER_SETTINGS>&lt;profile&gt; + &lt;Language id="CSS"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;/Language&gt; + &lt;Language id="EditorConfig"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="HTML"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; + &lt;/Language&gt; + &lt;Language id="HTTP Request"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Handlebars"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Ini"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="JSON"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Jade"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="JavaScript"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; + &lt;/Language&gt; + &lt;Language id="Markdown"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Properties"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="RELAX-NG"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="SQL"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="VueExpr"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="XML"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; + &lt;/Language&gt; + &lt;Language id="yaml"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; +&lt;/profile&gt;</RIDER_SETTINGS><FSReformatCode>True</FSReformatCode><CppMakePtrOrRefParameterConst>True</CppMakePtrOrRefParameterConst><CppMakeParameterConst>True</CppMakeParameterConst><CppClangTidyCleanupDescriptor abseil-cleanup-ctad="True" abseil-duration-addition="True" abseil-duration-comparison="True" abseil-duration-conversion-cast="True" abseil-duration-division="True" abseil-duration-factory-float="True" abseil-duration-factory-scale="True" abseil-duration-subtraction="True" abseil-duration-unnecessary-conversion="True" abseil-faster-strsplit-delimiter="True" abseil-redundant-strcat-calls="True" abseil-str-cat-append="True" abseil-string-find-startswith="True" abseil-string-find-str-contains="True" abseil-time-comparison="True" abseil-time-subtraction="True" abseil-upgrade-duration-conversions="True" android-cloexec-accept="True" android-cloexec-creat="True" android-cloexec-dup="True" android-cloexec-epoll-create="True" android-cloexec-epoll-create1="True" android-cloexec-fopen="True" android-cloexec-inotify-init="True" android-cloexec-inotify-init1="True" android-cloexec-memfd-create="True" android-cloexec-open="True" android-cloexec-pipe="True" boost-use-to-string="True" bugprone-argument-comment="True" bugprone-bool-pointer-implicit-conversion="True" bugprone-copy-constructor-init="True" bugprone-implicit-widening-of-multiplication-result="True" bugprone-inaccurate-erase="True" bugprone-macro-parentheses="True" bugprone-misplaced-operator-in-strlen-in-alloc="True" bugprone-misplaced-pointer-arithmetic-in-alloc="True" bugprone-move-forwarding-reference="True" bugprone-not-null-terminated-result="True" bugprone-parent-virtual-call="True" bugprone-posix-return="True" bugprone-redundant-branch-condition="True" bugprone-reserved-identifier="True" bugprone-shared-ptr-array-mismatch="True" bugprone-string-constructor="True" bugprone-string-integer-assignment="True" bugprone-stringview-nullptr="True" bugprone-suspicious-memset-usage="True" bugprone-suspicious-semicolon="True" bugprone-suspicious-string-compare="True" bugprone-swapped-arguments="True" bugprone-terminating-continue="True" bugprone-unused-raii="True" bugprone-virtual-near-miss="True" cert-dcl03-c="True" cert-dcl16-c="True" cert-dcl21-cpp="True" cert-oop11-cpp="True" cppcoreguidelines-explicit-virtual-functions="True" cppcoreguidelines-init-variables="True" cppcoreguidelines-prefer-member-initializer="True" cppcoreguidelines-pro-bounds-constant-array-index="True" cppcoreguidelines-pro-type-cstyle-cast="True" cppcoreguidelines-pro-type-member-init="True" cppcoreguidelines-pro-type-static-cast-downcast="True" cppcoreguidelines-virtual-class-destructor="True" darwin-dispatch-once-nonstatic="True" fuchsia-default-arguments-declarations="True" fuchsia-restrict-system-includes="True" google-build-explicit-make-pair="True" google-explicit-constructor="True" google-objc-avoid-nsobject-new="True" google-objc-function-naming="True" google-readability-braces-around-statements="True" google-readability-casting="True" google-readability-redundant-smartptr-get="True" google-readability-todo="True" google-upgrade-googletest-case="True" hicpp-braces-around-statements="True" hicpp-deprecated-headers="True" hicpp-explicit-conversions="True" hicpp-member-init="True" hicpp-move-const-arg="True" hicpp-named-parameter="True" hicpp-static-assert="True" hicpp-uppercase-literal-suffix="True" hicpp-use-auto="True" hicpp-use-emplace="True" hicpp-use-equals-default="True" hicpp-use-equals-delete="True" hicpp-use-noexcept="True" hicpp-use-nullptr="True" hicpp-use-override="True" llvm-else-after-return="True" llvm-header-guard="True" llvm-include-order="True" llvm-prefer-isa-or-dyn-cast-in-conditionals="True" llvm-prefer-register-over-unsigned="True" llvm-qualified-auto="True" llvm-twine-local="True" llvmlibc-restrict-system-libc-headers="True" misc-const-correctness="True" misc-definitions-in-headers="True" misc-macro-parentheses="True" misc-redundant-expression="True" misc-static-assert="True" misc-string-compare="True" misc-string-integer-assignment="True" misc-suspicious-string-compare="True" misc-uniqueptr-reset-release="True" misc-unused-alias-decls="True" misc-unused-parameters="True" misc-unused-raii="True" misc-unused-using-decls="True" modernize-avoid-bind="True" modernize-concat-nested-namespaces="True" modernize-deprecated-headers="True" modernize-deprecated-ios-base-aliases="True" modernize-loop-convert="True" modernize-macro-to-enum="True" modernize-make-shared="True" modernize-make-unique="True" modernize-pass-by-value="True" modernize-raw-string-literal="True" modernize-redundant-void-arg="True" modernize-replace-auto-ptr="True" modernize-replace-disallow-copy-and-assign-macro="True" modernize-replace-random-shuffle="True" modernize-return-braced-init-list="True" modernize-shrink-to-fit="True" modernize-use-auto="True" modernize-use-bool-literals="True" modernize-use-default-member-init="True" modernize-use-emplace="True" modernize-use-equals-default="True" modernize-use-equals-delete="True" modernize-use-nodiscard="True" modernize-use-noexcept="True" modernize-use-nullptr="True" modernize-use-override="True" modernize-use-trailing-return-type="True" modernize-use-uncaught-exceptions="True" modernize-use-using="True" objc-assert-equals="True" objc-property-declaration="True" objc-super-self="True" performance-faster-string-find="True" performance-for-range-copy="True" performance-inefficient-algorithm="True" performance-inefficient-vector-operation="True" performance-move-const-arg="True" performance-move-constructor-init="True" performance-noexcept-move-constructor="True" performance-trivially-destructible="True" performance-type-promotion-in-math-fn="True" performance-unnecessary-value-param="True" portability-restrict-system-includes="True" readability-braces-around-statements="True" readability-const-return-type="True" readability-container-contains="True" readability-container-data-pointer="True" readability-container-size-empty="True" readability-convert-member-functions-to-static="True" readability-delete-null-pointer="True" readability-duplicate-include="True" readability-else-after-return="True" readability-identifier-naming="True" readability-implicit-bool-conversion="True" readability-inconsistent-declaration-parameter-name="True" readability-isolate-declaration="True" readability-make-member-function-const="True" readability-misplaced-array-index="True" readability-named-parameter="True" readability-non-const-parameter="True" readability-qualified-auto="True" readability-redundant-access-specifiers="True" readability-redundant-control-flow="True" readability-redundant-declaration="True" readability-redundant-function-ptr-dereference="True" readability-redundant-member-init="True" readability-redundant-smartptr-get="True" readability-redundant-string-cstr="True" readability-redundant-string-init="True" readability-simplify-boolean-expr="True" readability-simplify-subscript-expr="True" readability-static-accessed-through-instance="True" readability-static-definition-in-anonymous-namespace="True" readability-string-compare="True" readability-uniqueptr-delete-release="True" readability-uppercase-literal-suffix="True" other-fixits="True" bugprone-standalone-empty="True" bugprone-unique-ptr-array-mismatch="True" cppcoreguidelines-misleading-capture-default-by-value="True" cppcoreguidelines-noexcept-destructor="True" cppcoreguidelines-noexcept-move-operations="True" cppcoreguidelines-noexcept-swap="True" cppcoreguidelines-use-default-member-init="True" llvmlibc-inline-function-decl="True" misc-include-cleaner="True" modernize-type-traits="True" modernize-use-std-print="True" performance-avoid-endl="True" performance-noexcept-destructor="True" performance-noexcept-swap="True" readability-operators-representation="True" /><CSReformatInactiveBranches>True</CSReformatInactiveBranches><FSharpReformatCode>True</FSharpReformatCode><CppMakeClassFinal>True</CppMakeClassFinal><CppMakeVariableConstexpr>True</CppMakeVariableConstexpr><CppPassValueParameterByConstReference>True</CppPassValueParameterByConstReference><CppRedundantDereferences>True</CppRedundantDereferences><CppReplaceIfWithIfConsteval>True</CppReplaceIfWithIfConsteval><CppRemoveRedundantConditionalExpressionDescriptor>True</CppRemoveRedundantConditionalExpressionDescriptor><CppSimplifyConditionalExpressionDescriptor>True</CppSimplifyConditionalExpressionDescriptor></Profile> + Archi + USE_TABS_ONLY + True + Required + Required + Required + Required + ExpressionBody + DefaultExpression + ExpressionBody + ExpressionBody + public protected internal private static extern new virtual abstract sealed override readonly unsafe volatile async + + Arithmetic, Shift, Bitwise, Conditional + END_OF_LINE + END_OF_LINE + USE_TABS_ONLY + False + False + + END_OF_LINE + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + END_OF_LINE + TOGETHER_SAME_LINE + NO_INDENT + Tab + END_OF_LINE + END_OF_LINE + 1 + 1 + False + False + False + True + False + + True + 1 + + END_OF_LINE + True + NEVER + NEVER + False + False + False + NEVER + False + False + NEVER + LINE_BREAK + LINE_BREAK + + True + True + False + END_OF_LINE + False + True + True + True + True + WRAP_IF_LONG + 65535 + False + USE_TABS_ONLY + USE_TABS_ONLY + Tab + False + USE_TABS_ONLY + USE_TABS_ONLY + USE_TABS_ONLY + USE_TABS_ONLY + USE_TABS_ONLY + 4 + Tab + True + 2147483646 + OnSingleLine + 4 + ByFirstAttr + OnSingleLine + False + 10000 + False + USE_TABS_ONLY + 4 + Tab + OnSingleLine + 4 + OnSingleLine + False + 10000 + False + <?xml version="1.0" encoding="utf-16"?> +<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern DisplayName="ArchiPattern" Priority="150"> + <Entry DisplayName="Public (Events and Delegates)"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Or> + <Kind Is="Delegate" /> + <Kind Is="Event" /> + </Or> + </And> + </Entry.Match> + <Entry.SortBy> + <Access /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Constants"> + <Entry.Match> + <Kind Is="Constant" /> + </Entry.Match> + <Entry.SortBy> + <Access /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Static (Fields, Properties and Indexers)"> + <Entry.Match> + <Or> + <And> + <Kind Is="Field" /> + <Static /> + </And> + <And> + <Kind Is="Autoproperty" /> + <Static /> + </And> + <And> + <Kind Is="Property" /> + <Static /> + </And> + <And> + <Kind Is="Indexer" /> + <Static /> + </And> + </Or> + </Entry.Match> + <Entry.SortBy> + <Access /> + <Readonly /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Non-static (Fields, Properties and Indexers)"> + <Entry.Match> + <And> + <Not> + <Static /> + </Not> + <Or> + <Kind Is="Field" /> + <Kind Is="Autoproperty" /> + <Kind Is="Property" /> + <Kind Is="Indexer" /> + </Or> + </And> + </Entry.Match> + <Entry.SortBy> + <Readonly /> + <Access /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Constructors"> + <Entry.Match> + <Kind Is="Constructor" /> + </Entry.Match> + <Entry.SortBy> + <Access /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interfaces"> + <Entry.Match> + <And> + <Kind Is="Member" /> + <ImplementsInterface /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Everything else"> + <Entry.SortBy> + <Access /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Nested"> + <Entry.Match> + <Kind Is="Type" /> + </Entry.Match> + <Entry.SortBy> + <Access /> + <Kind Is="Member" /> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + <TypePattern DisplayName="COM interfaces or structs"> + <TypePattern.Match> + <Or> + <And> + <Kind Is="Interface" /> + <Or> + <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> + <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> + </Or> + </And> + <Kind Is="Struct" /> + </Or> + </TypePattern.Match> + </TypePattern> + <TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <HasMember> + <And> + <Kind Is="Method" /> + <HasAttribute Name="Xunit.FactAttribute" Inherited="True" /> + </And> + </HasMember> + </And> + </TypePattern.Match> + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <Or> + <Kind Is="Constructor" /> + <And> + <Kind Is="Method" /> + <ImplementsInterface Name="System.IDisposable" /> + </And> + </Or> + </Entry.Match> + <Entry.SortBy> + <Kind Order="Constructor" /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="All other members" /> + <Entry DisplayName="Test Methods" Priority="100"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="Xunit.FactAttribute" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /> + </And> + </TypePattern.Match> + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <Or> + <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="All other members" /> + <Entry DisplayName="Test Methods" Priority="100"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> +</Patterns> + UseExplicitType + UseExplicitType + UseExplicitType + False + False + AES + API + ASF + EWCF + FA + FS + GC + GID + HTML + IASF + ID + IP + IPC + OK + OS + PICS + PIN + SC + SMS + TTL + URL + WCF + WS + WTF + WWW + XML + False + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="I" Suffix="" Style="AaBb" /></Policy> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> + + True + OnlyMarkers + Never + Never + True + Never + False + False + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + DO_NOTHING + LIVE_MONITOR + LIVE_MONITOR + NOTIFY + NOTIFY + + + True + NOTIFY + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + 8 + True + True + True + True + True + True + True + True + True diff --git a/ItemDispenser/ItemDispenser.cs b/ItemDispenser/ItemDispenser.cs index 7220157..b1724b9 100644 --- a/ItemDispenser/ItemDispenser.cs +++ b/ItemDispenser/ItemDispenser.cs @@ -1,101 +1,97 @@ using System; using System.Collections.Concurrent; +using System.Collections.Frozen; using System.Collections.Generic; using System.Composition; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; +using ArchiSteamFarm.Core; +using ArchiSteamFarm.Helpers.Json; +using ArchiSteamFarm.Plugins.Interfaces; using ArchiSteamFarm.Steam; using ArchiSteamFarm.Steam.Cards; using ArchiSteamFarm.Steam.Data; using ArchiSteamFarm.Steam.Storage; -using ArchiSteamFarm.Collections; -using ArchiSteamFarm.Core; -using ArchiSteamFarm.Plugins.Interfaces; -using JetBrains.Annotations; -using System.Text.Json; -using ArchiSteamFarm.Helpers.Json; -namespace ItemDispenser { - [Export(typeof(IPlugin))] - public class ItemDispenser : IBotTradeOffer, IBotModules { +namespace ItemDispenser; - private readonly ConcurrentDictionary> BotSettings = new(); +[Export(typeof(IPlugin))] - public string Name => nameof(ItemDispenser); +internal sealed class ItemDispenser : IBotTradeOffer, IBotModules { + private static readonly ConcurrentDictionary>> BotSettings = new(); - public Version Version => typeof(ItemDispenser).Assembly.GetName().Version ?? new Version("0.0.0.0"); + public string Name => nameof(ItemDispenser); - public async Task OnBotTradeOffer(Bot bot, TradeOffer tradeOffer) { - if (tradeOffer == null) { - ASF.ArchiLogger.LogNullError(tradeOffer); - return false; - } + public Version Version => typeof(ItemDispenser).Assembly.GetName().Version ?? new Version("0.0.0.0"); - //If we receiveing something in return, and donations is not accepted - ignore. - if (tradeOffer.ItemsToReceiveReadOnly.Count > 0 && !bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.AcceptDonations)) { - return false; - } - byte? holdDuration = await bot.GetTradeHoldDuration(tradeOffer.OtherSteamID64, tradeOffer.TradeOfferID).ConfigureAwait(false); + public Task OnBotInitModules(Bot bot, IReadOnlyDictionary? additionalConfigProperties) { + ArgumentNullException.ThrowIfNull(bot); - if (!holdDuration.HasValue) { - // If we can't get trade hold duration, ignore - return false; - } + if (additionalConfigProperties == null) { + _ = BotSettings.TryRemove(bot, out _); + + return Task.CompletedTask; + } + + if (!additionalConfigProperties.TryGetValue("Rudokhvist.DispenseItems", out JsonElement jsonElement)) { + _ = BotSettings.TryRemove(bot, out _); + + return Task.CompletedTask; + } - // If user has a trade hold, we add extra logic - if (holdDuration.Value > 0) { - // If trade hold duration exceeds our max, or user asks for cards with short lifespan, reject the trade - if ((holdDuration.Value > (ASF.GlobalConfig?.MaxTradeHoldDuration ?? 0)) || tradeOffer.ItemsToGiveReadOnly.Any(item => ((item.Type == Asset.EType.FoilTradingCard) || (item.Type == Asset.EType.TradingCard)) && CardsFarmer.SalesBlacklist.Contains(item.RealAppID))) { - return false; + Dictionary<(uint AppID, ulong ContextID), HashSet> botSettings = []; + + try { + foreach (DispenseItem? dispenseItem in jsonElement.EnumerateArray().Select(static elem => elem.ToJsonObject())) { + if (dispenseItem == null) { + continue; } - } - //if we can't get settings for this bot for some reason - ignore - if (!BotSettings.TryGetValue(bot, out ConcurrentHashSet? ItemsToDispense)) { - return false; - } + (uint AppID, ulong ContextID) key = (dispenseItem.AppID, dispenseItem.ContextID); - foreach (Asset item in tradeOffer.ItemsToGiveReadOnly) { - if (!ItemsToDispense.Any(sample => - (sample.AppID == item.AppID) && - (sample.ContextID == item.ContextID) && - (sample.Types.Count <= 0 || sample.Types.Any(type => type == item.Type)) - )) { - return false; + if (!botSettings.TryGetValue(key, out HashSet? types)) { + types = []; + botSettings[key] = types; } + + types.UnionWith(dispenseItem.Types); } - return true; - } + BotSettings[bot] = botSettings.ToFrozenDictionary(static kv => kv.Key, static kv => kv.Value.ToFrozenSet()); + } catch (Exception e) { + bot.ArchiLogger.LogGenericException(e); + bot.ArchiLogger.LogGenericError("Item Dispenser configuration is wrong!"); - public Task OnLoaded() { - ASF.ArchiLogger.LogGenericInfo("Item Dispenser Plugin by Rudokhvist, powered by ginger cats"); - return Task.CompletedTask; + _ = BotSettings.TryRemove(bot, out _); } + return Task.CompletedTask; + } - public Task OnBotInitModules(Bot bot, IReadOnlyDictionary? additionalConfigProperties) { - - if (additionalConfigProperties == null) { - BotSettings.AddOrUpdate(bot, [], (k, v) => []); - return Task.CompletedTask; - } + public async Task OnBotTradeOffer(Bot bot, TradeOffer tradeOffer) { + ArgumentNullException.ThrowIfNull(bot); + ArgumentNullException.ThrowIfNull(tradeOffer); - if (!additionalConfigProperties.TryGetValue("Rudokhvist.DispenseItems", out JsonElement jToken)) { - BotSettings.AddOrUpdate(bot, [], (k, v) => []); - return Task.CompletedTask; - } + if (!BotSettings.TryGetValue(bot, out FrozenDictionary<(uint AppID, ulong ContextID), FrozenSet>? itemsToDispense)) { + // Settings not declared for this bot, skip overhead + return false; + } - ConcurrentHashSet dispenseItems = []; - try { - dispenseItems.UnionWith(jToken.EnumerateArray().Select(static elem => elem.ToJsonObject()).OfType()); - BotSettings.AddOrUpdate(bot, dispenseItems, (k, v) => dispenseItems); - } catch { - bot.ArchiLogger.LogGenericError("Item Dispenser configuration is wrong!"); - BotSettings.AddOrUpdate(bot, [], (k, v) => []); - } - return Task.CompletedTask; + // If we're receiving something in return, and donations is not accepted - ignore + if ((tradeOffer.ItemsToReceiveReadOnly.Count > 0) && !bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.AcceptDonations)) { + return false; } + byte? holdDuration = await bot.GetTradeHoldDuration(tradeOffer.OtherSteamID64, tradeOffer.TradeOfferID).ConfigureAwait(false); + + return holdDuration != null && (!(holdDuration > 0) || holdDuration.Value <= (ASF.GlobalConfig?.MaxTradeHoldDuration ?? 0)) && !tradeOffer.ItemsToGiveReadOnly.Any(static item => item.Type is Asset.EType.FoilTradingCard or Asset.EType.TradingCard && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)) +&& tradeOffer.ItemsToGiveReadOnly.All(item => itemsToDispense.TryGetValue((item.AppID, item.ContextID), out FrozenSet? dispense) && ((dispense.Count == 0) || dispense.Contains(item.Type))); + } + + public Task OnLoaded() { + ASF.ArchiLogger.LogGenericInfo("Item Dispenser Plugin by Rudokhvist, powered by ginger cats"); + + return Task.CompletedTask; } }