├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── Directory.Build.props ├── Directory.Packages.props ├── LICENSE ├── MBA.sln ├── README.md ├── assets ├── README.md ├── Resource │ ├── Base │ │ ├── image │ │ │ ├── Arona.png │ │ │ ├── Buttons │ │ │ │ ├── Back.png │ │ │ │ ├── Close.png │ │ │ │ ├── CloseFullscreen.png │ │ │ │ ├── Home.png │ │ │ │ ├── Pass.png │ │ │ │ ├── Plus.png │ │ │ │ └── ThreeStarsFlag.png │ │ │ ├── Cafe │ │ │ │ ├── CloseSidebar.png │ │ │ │ ├── StudentAffection.png │ │ │ │ ├── StudentAffection1.png │ │ │ │ └── StudentAffection2.png │ │ │ ├── Campaign │ │ │ │ └── Campaign.png │ │ │ ├── Mailbox │ │ │ │ └── Mailbox.png │ │ │ ├── TacticalChallenge │ │ │ │ ├── Pyroxene.png │ │ │ │ └── ZeroTicket1.png │ │ │ └── Tasks │ │ │ │ └── Tasks.png │ │ ├── model │ │ │ └── ocr │ │ │ │ ├── README.md │ │ │ │ ├── det.onnx │ │ │ │ ├── keys.txt │ │ │ │ └── rec.onnx │ │ ├── pipeline │ │ │ ├── Bounty.json │ │ │ ├── Buttons.json │ │ │ ├── Cafe.json │ │ │ ├── Campaign.json │ │ │ ├── Club.json │ │ │ ├── Commissions.json │ │ │ ├── Crafting.json │ │ │ ├── Mailbox.json │ │ │ ├── ProcessingNotice.json │ │ │ ├── Scrimmage.json │ │ │ ├── Shop.json │ │ │ ├── StartUp.json │ │ │ ├── TacticalChallenge.json │ │ │ ├── Tasks.json │ │ │ ├── Test.json │ │ │ └── Utils.json │ │ └── properties.json │ ├── EN │ │ ├── image │ │ │ ├── Campaign │ │ │ │ └── TacticalChallenge │ │ │ │ │ └── SkipTactics.png │ │ │ ├── Crafting │ │ │ │ ├── MaterialFusion.png │ │ │ │ └── MaterialSynthesis.png │ │ │ └── Tasks │ │ │ │ ├── Claim.png │ │ │ │ └── ClaimAll.png │ │ ├── pipeline │ │ │ ├── OCRPartialTasks.json │ │ │ └── TemplateMatchPartialTasks.json │ │ └── properties.json │ ├── SC │ │ ├── image │ │ │ ├── Campaign │ │ │ │ └── TacticalChallenge │ │ │ │ │ └── SkipTactics.png │ │ │ ├── Crafting │ │ │ │ ├── MaterialFusion.png │ │ │ │ └── MaterialSynthesis.png │ │ │ └── Tasks │ │ │ │ ├── Claim.png │ │ │ │ └── ClaimAll.png │ │ ├── model │ │ │ └── ocr │ │ │ │ ├── README.md │ │ │ │ ├── det.onnx │ │ │ │ ├── keys.txt │ │ │ │ └── rec.onnx │ │ ├── pipeline │ │ │ ├── Bounty.json │ │ │ ├── Commissions.json │ │ │ ├── DisabledTasks.json │ │ │ ├── OCRPartialTasks.json │ │ │ ├── Scrimmage.json │ │ │ └── TemplateMatchPartialTasks.json │ │ └── properties.json │ ├── TC │ │ ├── image │ │ │ ├── Campaign │ │ │ │ └── TacticalChallenge │ │ │ │ │ └── SkipTactics.png │ │ │ ├── Crafting │ │ │ │ ├── MaterialFusion.png │ │ │ │ └── MaterialSynthesis.png │ │ │ └── Tasks │ │ │ │ ├── Claim.png │ │ │ │ └── ClaimAll.png │ │ ├── model │ │ │ └── ocr │ │ │ │ ├── README.md │ │ │ │ ├── det.onnx │ │ │ │ ├── keys.txt │ │ │ │ └── rec.onnx │ │ ├── pipeline │ │ │ ├── OCRPartialTasks.json │ │ │ └── TemplateMatchPartialTasks.json │ │ └── properties.json │ ├── controller_config.json │ └── pipeline.schema.json └── logo.ico ├── src ├── MBA.Cli │ ├── MBA.Cli.csproj │ ├── Program.cs │ ├── Properties │ │ ├── PublishProfiles │ │ │ ├── linux-arm64-single-cut.pubxml │ │ │ ├── linux-x64-single-cut.pubxml │ │ │ ├── osx-arm64-single-cut.pubxml │ │ │ ├── osx-x64-single-cut.pubxml │ │ │ ├── win-arm64-single-cut.pubxml │ │ │ ├── win-x64-single-cut.pubxml │ │ │ └── win-x64-single-runtime-relied.pubxml │ │ └── launchSettings.json │ └── packages.lock.json └── MBA.Core │ ├── Data │ ├── Config.cs │ ├── ConfigContext.cs │ ├── DiffTasks.cs │ └── GlobalInfo.cs │ ├── Enums │ ├── Bounty.cs │ ├── Commissions.cs │ ├── GameLanguageServer.cs │ ├── Scrimmage.cs │ └── TaskType.cs │ ├── Extensions │ └── ConfigTimesExtension.cs │ ├── MBA.Core.csproj │ ├── Maa.cs │ ├── Managers │ ├── ConfigManager.cs │ ├── LogManager.cs │ ├── TaskManager.cs │ └── VersionManager.cs │ ├── Sensei.cs │ └── packages.lock.json └── tools ├── ChangelogGenerator ├── .gitignore ├── changelog_generator.py └── start.bat ├── ImageCropper ├── README.md ├── colormatcher.py ├── dst │ └── .gitkeep ├── main.py ├── requirements.txt ├── roi.py ├── roimage.py ├── src │ └── .gitkeep └── start.bat └── ResourceReviewer └── main.py /.editorconfig: -------------------------------------------------------------------------------- 1 | ############################### 2 | # Core EditorConfig Options # 3 | ############################### 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | end_of_line = lf 13 | max_line_length = off 14 | 15 | # YAML indentation 16 | [*.{yml,yaml}] 17 | indent_size = 2 18 | 19 | # XML indentation 20 | [*.{csproj,xml}] 21 | indent_size = 2 22 | 23 | [**.{axaml,xaml}] 24 | indent_size = 4 25 | 26 | [*.json] 27 | indent_size = 4 28 | 29 | ############################### 30 | # .NET Coding Conventions # 31 | ############################### 32 | [*.{cs,vb}] 33 | # Organize usings 34 | dotnet_sort_system_directives_first = true 35 | # this. preferences 36 | dotnet_style_qualification_for_field = false:silent 37 | dotnet_style_qualification_for_property = false:silent 38 | dotnet_style_qualification_for_method = false:silent 39 | dotnet_style_qualification_for_event = false:silent 40 | # Language keywords vs BCL types preferences 41 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 42 | dotnet_style_predefined_type_for_member_access = true:silent 43 | # Parentheses preferences 44 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 45 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 46 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 47 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 48 | # Modifier preferences 49 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 50 | dotnet_style_readonly_field = true:suggestion 51 | # Expression-level preferences 52 | dotnet_style_object_initializer = true:suggestion 53 | dotnet_style_collection_initializer = true:suggestion 54 | dotnet_style_explicit_tuple_names = true:suggestion 55 | dotnet_style_null_propagation = true:suggestion 56 | dotnet_style_coalesce_expression = true:suggestion 57 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent 58 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 59 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 60 | dotnet_style_prefer_auto_properties = true:silent 61 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 62 | dotnet_style_prefer_conditional_expression_over_return = true:silent 63 | 64 | ############################### 65 | # Naming Conventions # 66 | ############################### 67 | # Style Definitions (From Roslyn) 68 | 69 | # Non-private static fields are PascalCase 70 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion 71 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields 72 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style 73 | 74 | dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field 75 | dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected 76 | dotnet_naming_symbols.non_private_static_fields.required_modifiers = static 77 | 78 | dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case 79 | 80 | # Constants are PascalCase 81 | dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion 82 | dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants 83 | dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style 84 | 85 | dotnet_naming_symbols.constants.applicable_kinds = field, local 86 | dotnet_naming_symbols.constants.required_modifiers = const 87 | 88 | dotnet_naming_style.constant_style.capitalization = pascal_case 89 | 90 | # Static fields are camelCase and start with s_ 91 | dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion 92 | dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields 93 | dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style 94 | 95 | dotnet_naming_symbols.static_fields.applicable_kinds = field 96 | dotnet_naming_symbols.static_fields.required_modifiers = static 97 | 98 | dotnet_naming_style.static_field_style.capitalization = camel_case 99 | dotnet_naming_style.static_field_style.required_prefix = _ 100 | 101 | # Instance fields are camelCase and start with _ 102 | dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion 103 | dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields 104 | dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style 105 | 106 | dotnet_naming_symbols.instance_fields.applicable_kinds = field 107 | 108 | dotnet_naming_style.instance_field_style.capitalization = camel_case 109 | dotnet_naming_style.instance_field_style.required_prefix = _ 110 | 111 | # Locals and parameters are camelCase 112 | dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion 113 | dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters 114 | dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style 115 | 116 | dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local 117 | 118 | dotnet_naming_style.camel_case_style.capitalization = camel_case 119 | 120 | # Local functions are PascalCase 121 | dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion 122 | dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions 123 | dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style 124 | 125 | dotnet_naming_symbols.local_functions.applicable_kinds = local_function 126 | 127 | dotnet_naming_style.local_function_style.capitalization = pascal_case 128 | 129 | # By default, name items with PascalCase 130 | dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion 131 | dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members 132 | dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style 133 | 134 | dotnet_naming_symbols.all_members.applicable_kinds = * 135 | 136 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 137 | 138 | ############################### 139 | # C# Coding Conventions # 140 | ############################### 141 | [*.cs] 142 | # var preferences 143 | csharp_style_var_for_built_in_types = true:silent 144 | csharp_style_var_when_type_is_apparent = true:silent 145 | csharp_style_var_elsewhere = true:silent 146 | # Expression-bodied members 147 | csharp_style_expression_bodied_methods = false:silent 148 | csharp_style_expression_bodied_constructors = false:silent 149 | csharp_style_expression_bodied_operators = false:silent 150 | csharp_style_expression_bodied_properties = true:silent 151 | csharp_style_expression_bodied_indexers = true:silent 152 | csharp_style_expression_bodied_accessors = true:silent 153 | # Pattern matching preferences 154 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 155 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 156 | # Null-checking preferences 157 | csharp_style_throw_expression = true:suggestion 158 | csharp_style_conditional_delegate_call = true:suggestion 159 | # Modifier preferences 160 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion 161 | # Expression-level preferences 162 | csharp_prefer_braces = true:silent 163 | csharp_style_deconstructed_variable_declaration = true:suggestion 164 | csharp_prefer_simple_default_expression = true:suggestion 165 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 166 | csharp_style_inlined_variable_declaration = true:suggestion 167 | 168 | csharp_style_namespace_declarations = file_scoped:warning 169 | 170 | ############################### 171 | # C# Formatting Rules # 172 | ############################### 173 | # New line preferences 174 | csharp_new_line_before_open_brace = all 175 | csharp_new_line_before_else = true 176 | csharp_new_line_before_catch = true 177 | csharp_new_line_before_finally = true 178 | csharp_new_line_before_members_in_object_initializers = true 179 | csharp_new_line_before_members_in_anonymous_types = true 180 | csharp_new_line_between_query_expression_clauses = true 181 | # Indentation preferences 182 | csharp_indent_case_contents = true 183 | csharp_indent_switch_labels = true 184 | csharp_indent_labels = flush_left 185 | # Space preferences 186 | csharp_space_after_cast = false 187 | csharp_space_after_keywords_in_control_flow_statements = true 188 | csharp_space_between_method_call_parameter_list_parentheses = false 189 | csharp_space_between_method_declaration_parameter_list_parentheses = false 190 | csharp_space_between_parentheses = false 191 | csharp_space_before_colon_in_inheritance_clause = true 192 | csharp_space_after_colon_in_inheritance_clause = true 193 | csharp_space_around_binary_operators = before_and_after 194 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 195 | csharp_space_between_method_call_name_and_opening_parenthesis = false 196 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 197 | # Wrapping preferences 198 | csharp_preserve_single_line_statements = true 199 | csharp_preserve_single_line_blocks = true 200 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.cs text eol=crlf 3 | *.csproj text eol=crlf 4 | *.sln text eol=crlf 5 | *.ps1 text eol=crlf 6 | *.sh text eol=lf 7 | 8 | *.json text eol=crlf 9 | *.md text eol=crlf 10 | *.yaml text eol=crlf 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - "**" 8 | paths: 9 | - ".github/workflows/ci.yml" 10 | - "src/**" 11 | - "*.sln" 12 | - "*.props" 13 | tags: 14 | - "v*" 15 | 16 | pull_request: 17 | branches: 18 | - "**" 19 | paths: 20 | - ".github/workflows/ci.yml" 21 | - "src/**" 22 | - "*.sln" 23 | - "*.props" 24 | 25 | jobs: 26 | meta: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v3 30 | with: 31 | fetch-depth: 0 32 | - id: meta 33 | run: | 34 | is_release=${{ startsWith(github.ref, 'refs/tags/v') }} 35 | tag=$(git describe --tags --match "v*" ${{ github.ref }} || true) 36 | if [[ $tag != v* ]]; then 37 | tag=$(date "+v0.0.0-%y%m%d-$(git rev-parse --short HEAD)") 38 | fi 39 | if ! $($is_release) ; then 40 | prefix=${tag%-*-*} 41 | suffix=${tag#$prefix-} 42 | next=${prefix##*.} 43 | ((++next)) 44 | prefix=${prefix%.*} 45 | tag="$prefix.$next-Preview.$suffix" 46 | fi 47 | echo tag=$tag | tee -a $GITHUB_OUTPUT 48 | echo version=${tag#v} | tee -a $GITHUB_OUTPUT 49 | echo is_release=$is_release | tee -a $GITHUB_OUTPUT 50 | outputs: 51 | tag: ${{ steps.meta.outputs.tag }} 52 | version: ${{ steps.meta.outputs.version }} 53 | is_release: ${{ steps.meta.outputs.is_release }} 54 | 55 | publish: 56 | needs: [meta] 57 | strategy: 58 | fail-fast: false 59 | matrix: 60 | project: [MBA.Cli] 61 | os: [win, linux, osx] 62 | arch: [x64, arm64] 63 | suffix: [-single-cut] 64 | dotnet: ['7.0'] 65 | include: 66 | - project: MBA.Cli 67 | os: win 68 | arch: x64 69 | suffix: -single-runtime-relied 70 | dotnet: '7.0' 71 | env: 72 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 73 | PUBLISH_NAME: ${{ matrix.project }}-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.suffix }}-${{ needs.meta.outputs.tag }} 74 | PUBLISH_PATH: ./Publish #./Publish/${{ matrix.project }}-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.suffix }}/ 75 | CSPROJ_PATH: ./src/${{ matrix.project }}/${{ matrix.project }}.csproj 76 | PUBXML_PATH: ./src/${{ matrix.project }}/Properties/PublishProfiles/${{ matrix.os }}-${{ matrix.arch }}${{ matrix.suffix }}.pubxml 77 | 78 | runs-on: windows-latest 79 | steps: 80 | - uses: actions/checkout@v3 81 | with: 82 | submodules: true 83 | - uses: actions/setup-dotnet@v3 84 | with: 85 | dotnet-version: ${{ matrix.dotnet }} 86 | cache: true 87 | cache-dependency-path: '**/packages.lock.json' 88 | - run: dotnet restore --locked-mode 89 | 90 | - run: dotnet publish ${{ env.CSPROJ_PATH }} --no-restore -p:Version=${{ needs.meta.outputs.version }} -p:PublishProfile=${{ env.PUBXML_PATH }} 91 | 92 | - uses: actions/upload-artifact@v3 93 | if: always() 94 | with: 95 | name: ${{ env.PUBLISH_NAME }} 96 | path: ${{ env.PUBLISH_PATH }} 97 | 98 | - name: Pack 99 | if: ${{ needs.meta.outputs.is_release == 'true' }} 100 | working-directory: ${{ env.PUBLISH_PATH }} 101 | run: 7z a -r ../${{ env.PUBLISH_NAME }}.zip ./* 102 | 103 | - uses: softprops/action-gh-release@v1 104 | if: ${{ needs.meta.outputs.is_release == 'true' }} 105 | with: 106 | body_path: CHANGELOG.md 107 | prerelease: true 108 | files: ${{ env.PUBLISH_NAME }}.zip 109 | tag_name: ${{ needs.meta.outputs.tag }} 110 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # Tye 66 | .tye/ 67 | 68 | # ASP.NET Scaffolding 69 | ScaffoldingReadMe.txt 70 | 71 | # StyleCop 72 | StyleCopReport.xml 73 | 74 | # Files built by Visual Studio 75 | *_i.c 76 | *_p.c 77 | *_h.h 78 | *.ilk 79 | *.meta 80 | *.obj 81 | *.iobj 82 | *.pch 83 | *.pdb 84 | *.ipdb 85 | *.pgc 86 | *.pgd 87 | *.rsp 88 | *.sbr 89 | *.tlb 90 | *.tli 91 | *.tlh 92 | *.tmp 93 | *.tmp_proj 94 | *_wpftmp.csproj 95 | *.log 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | # *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | #*.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio LightSwitch build output 300 | **/*.HTMLClient/GeneratedArtifacts 301 | **/*.DesktopClient/GeneratedArtifacts 302 | **/*.DesktopClient/ModelManifest.xml 303 | **/*.Server/GeneratedArtifacts 304 | **/*.Server/ModelManifest.xml 305 | _Pvt_Extensions 306 | 307 | # Paket dependency manager 308 | .paket/paket.exe 309 | paket-files/ 310 | 311 | # FAKE - F# Make 312 | .fake/ 313 | 314 | # CodeRush personal settings 315 | .cr/personal 316 | 317 | # Python Tools for Visual Studio (PTVS) 318 | __pycache__/ 319 | *.pyc 320 | 321 | # Cake - Uncomment if you are using it 322 | # tools/** 323 | # !tools/packages.config 324 | 325 | # Tabs Studio 326 | *.tss 327 | 328 | # Telerik's JustMock configuration file 329 | *.jmconfig 330 | 331 | # BizTalk build output 332 | *.btp.cs 333 | *.btm.cs 334 | *.odx.cs 335 | *.xsd.cs 336 | 337 | # OpenCover UI analysis results 338 | OpenCover/ 339 | 340 | # Azure Stream Analytics local run output 341 | ASALocalRun/ 342 | 343 | # MSBuild Binary and Structured Log 344 | *.binlog 345 | 346 | # NVidia Nsight GPU debugger configuration file 347 | *.nvuser 348 | 349 | # MFractors (Xamarin productivity tool) working folder 350 | .mfractor/ 351 | 352 | # Local History for Visual Studio 353 | .localhistory/ 354 | 355 | # BeatPulse healthcheck temp database 356 | healthchecksdb 357 | 358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 359 | MigrationBackup/ 360 | 361 | # Ionide (cross platform F# VS Code tools) working folder 362 | .ionide/ 363 | 364 | # Fody - auto-generated XML schema 365 | FodyWeavers.xsd 366 | 367 | ## 368 | ## Visual studio for Mac 369 | ## 370 | 371 | 372 | # globs 373 | Makefile.in 374 | *.userprefs 375 | *.usertasks 376 | config.make 377 | config.status 378 | aclocal.m4 379 | install-sh 380 | autom4te.cache/ 381 | *.tar.gz 382 | tarballs/ 383 | test-results/ 384 | 385 | # Mac bundle stuff 386 | *.dmg 387 | *.app 388 | 389 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 390 | # General 391 | .DS_Store 392 | .AppleDouble 393 | .LSOverride 394 | 395 | # Icon must end with two \r 396 | Icon 397 | 398 | 399 | # Thumbnails 400 | ._* 401 | 402 | # Files that might appear in the root of a volume 403 | .DocumentRevisions-V100 404 | .fseventsd 405 | .Spotlight-V100 406 | .TemporaryItems 407 | .Trashes 408 | .VolumeIcon.icns 409 | .com.apple.timemachine.donotpresent 410 | 411 | # Directories potentially created on remote AFP share 412 | .AppleDB 413 | .AppleDesktop 414 | Network Trash Folder 415 | Temporary Items 416 | .apdisk 417 | 418 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 419 | # Windows thumbnail cache files 420 | Thumbs.db 421 | ehthumbs.db 422 | ehthumbs_vista.db 423 | 424 | # Dump file 425 | *.stackdump 426 | 427 | # Folder config file 428 | [Dd]esktop.ini 429 | 430 | # Recycle Bin used on file shares 431 | $RECYCLE.BIN/ 432 | 433 | # Windows Installer files 434 | *.cab 435 | *.msi 436 | *.msix 437 | *.msm 438 | *.msp 439 | 440 | # Windows shortcuts 441 | *.lnk 442 | 443 | # JetBrains Rider 444 | .idea/ 445 | *.sln.iml 446 | 447 | ## 448 | ## Visual Studio Code 449 | ## 450 | .vscode/* 451 | !.vscode/settings.json 452 | !.vscode/tasks.json 453 | !.vscode/launch.json 454 | !.vscode/extensions.json 455 | 456 | # MBA 457 | tools/ImageCropper/src/* 458 | tools/ImageCropper/dst/* 459 | !tools/ImageCropper/src/.gitkeep 460 | !tools/ImageCropper/dst/.gitkeep 461 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[typescript][javascript][json]": { 3 | "editor.formatOnSave": true, 4 | "editor.defaultFormatter": "esbenp.prettier-vscode", 5 | "editor.insertSpaces": true, 6 | "editor.tabSize": 4, 7 | "editor.indentSize": "tabSize" 8 | }, 9 | "[python]": { 10 | "editor.defaultFormatter": "ms-python.black-formatter" 11 | }, 12 | "python.formatting.provider": "none", 13 | "json.schemas": [ 14 | { 15 | "fileMatch": ["/assets/Resource/**/*.json"], 16 | "url": "/assets/Resource/pipeline.schema.json" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v0.2.1 2 | 3 | ### 改进 4 | 5 | - 更新简中 OCR 字段 @Dissectum 6 | - 适配国际服新 UI @Dissectum 7 | - 调整 TacticalChallenge 等待方式 @Dissectum 8 | 9 | ### 其他 10 | 11 | - Update ImageCropper @Dissectum 12 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | linux-arm64;linux-x64;osx-arm64;osx-x64;win-arm64;win-x64 6 | true 7 | embedded 8 | enable 9 | enable 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | $([System.DateTime]::Now.Year) 22 | 23 | 24 | 25 | 26 | 1.0.0-dev 27 | MAA Team 28 | MAA Team 29 | MAA Assistant Arknights 30 | Copyright © 2021-$(CurrentYear) MAA Team and Contributers. All rights reserved. 31 | 32 | 33 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /MBA.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33712.159 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBA.Core", "src\MBA.Core\MBA.Core.csproj", "{CA1365AD-1916-4359-AAC9-F54DFBA50C07}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBA.Cli", "src\MBA.Cli\MBA.Cli.csproj", "{C54D42A5-D657-490B-8CE2-00FC20D50ADF}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{0FAFA8D8-F731-463D-85C2-BB92B63EDED4}" 11 | ProjectSection(SolutionItems) = preProject 12 | Directory.Build.props = Directory.Build.props 13 | Directory.Packages.props = Directory.Packages.props 14 | README.md = README.md 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {CA1365AD-1916-4359-AAC9-F54DFBA50C07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {CA1365AD-1916-4359-AAC9-F54DFBA50C07}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {CA1365AD-1916-4359-AAC9-F54DFBA50C07}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {CA1365AD-1916-4359-AAC9-F54DFBA50C07}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {C54D42A5-D657-490B-8CE2-00FC20D50ADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {C54D42A5-D657-490B-8CE2-00FC20D50ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {C54D42A5-D657-490B-8CE2-00FC20D50ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {C54D42A5-D657-490B-8CE2-00FC20D50ADF}.Release|Any CPU.Build.0 = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | GlobalSection(ExtensibilityGlobals) = postSolution 36 | SolutionGuid = {83FFA662-3AC7-407E-A01C-FA31B346C718} 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > 由于开发者是个单线程生物,在 MaaFramework 的一些基础设施可用之前,此仓库中断维护(咕了)。 3 | > 4 | > Since the developer is a single-threaded creature, this repository is in hiatus until some of the MaaFramework infrastructure is available. 5 | 6 |
7 | LOGO 8 | 9 | # MBA 10 | 11 | 基于 MAA 全新架构的 BA 小助手 12 | 13 | 图像技术 + 模拟控制,解放双手,不再点点点! 14 | 15 | 由 [MaaFramework](https://github.com/MaaAssistantArknights/MaaFramework) 强力驱动! 16 | 17 |
18 | 19 | ## 下载地址 20 | 21 | - [正式版](https://github.com/MaaAssistantArknights/MBA/releases/latest) 22 | - [预览版](https://github.com/MaaAssistantArknights/MBA/actions/workflows/ci.yml) 23 | 24 | ### 注意 25 | 26 | - 打不开 / 一闪而过可能是存在中文路径。 27 | - 想要开箱即用,请直接下载 `MBA.Cli-single-cut` 包。 28 | - `runtime-relied` 包在运行前需要预先安装 [.NET 运行时 7.0](https://dotnet.microsoft.com/zh-cn/download/dotnet/7.0) 29 | - 其他系统、架构想要下载预构建好的 `runtime-relied` 包,欢迎 pr 或提 issue。 30 | 31 | ## 使用说明 32 | 33 | ### 基本说明 34 | 35 | 1. 请根据 [模拟器支持情况](https://maa.plus/docs/1.3-模拟器支持.html),进行对应的操作。 36 | 2. 修改模拟器分辨率为 `16:9` 比例,最低 `1280 * 720`,更高不限。 37 | 3. 开始使用吧! 38 | 39 | ## 开发相关 40 | 41 | - `tools/CropRoi` 可以用来裁剪图片和获取 ROI 42 | - Pipeline 协议请参考 [MaaFramework 的文档 (Document of MaaFramework)](https://github.com/MaaAssistantArknights/MaaFramework/blob/main/docs/zh_cn/3.3-%E4%BB%BB%E5%8A%A1%E6%B5%81%E6%B0%B4%E7%BA%BF%E5%8D%8F%E8%AE%AE.md) 43 | - [多语言支持](./assets/README.md#多语言支持) 44 | - [Multi-language support](./assets/README.md#multi-language-support) 45 | 46 | ## Join us 47 | 用户反馈 / 开发 QQ 群:205135027 48 | 49 | ## How to build 50 | 51 | 0. Clone 本仓库 52 | 53 | 1. 编译环境准备 54 | 55 | 下载 [.NET 7.0 SDK](https://dotnet.microsoft.com/zh-cn/download/dotnet/7.0) 或 Visual Studio 2022 56 | 57 | 2. Build 58 | 59 | - 使用 VS 生成 60 | 61 | - 使用命令行生成 62 | 63 | ```sh 64 | cd MBA/src/MBA.Cli 65 | dotnet build 66 | # 或专为安装了运行时的 winX64 用户打包 67 | dotnet build -r win-x64 -c Release -p:PublishSingleFile=true --self-contained false 68 | # 或者发布一个自包含应用 69 | dotnet publish -r win-x64 -c Release -p:PublishSingleFile=true --self-contained true -p:PublishTrimmed=true 70 | ``` 71 | 72 | 3. 生成的二进制及相关资源文件在 `MBA\src\MBA.Cli\bin` 目录下 73 | 74 | ## 致谢 75 | 76 | ### 开源库 77 | 78 | - [MaaFramework](https://github.com/MaaAssistantArknights/MaaFramework):自动化测试框架 79 | - [MaaAgentBinary](https://github.com/MaaAssistantArknights/MaaAgentBinary): Maa 代理的预构建文件 80 | - [MaaToolKit.Extensions](https://github.com/moomiji/MaaToolKit.Extensions):MaaFramework 的 C# 包装 81 | - [Serilog](https://github.com/serilog/serilog):C# 日志记录库 82 | 83 | ## 画大饼 84 | 85 | ### v1.0 86 | 87 | - [ ] Daily 88 | 89 | - Home 90 | - [x] Tasks 91 | - [x] Mailbox 92 | - [x] Cafe : TODO 需要缩放 93 | - [ ] Lesson : 需要判断颜色 + 遍历所有可选项 94 | - [x] Club 95 | - [ ] Crafting : 需要判断颜色 + 遍历所有可选项 96 | - [ ] Shop 97 | - Campaign 98 | - [x] Tactical Challenge 99 | - [x] Scrimmage 100 | - [x] Commissions 101 | - [x] Bounty 102 | - Mission 103 | - [ ] Normal 104 | - [ ] Hard 105 | - [ ] Event 106 | 107 | - [ ] Weekly 108 | 109 | - [ ] Support SC / TC / EN / JP 110 | 111 | ### v2.0 112 | 113 | - [ ] 关卡掉落识别 114 | - [ ] 仓库识别 115 | - [ ] 材料需求计算 116 | - [ ] 活动关卡导航 117 | 118 | ### v3.0 119 | 120 | - [ ] 自动活动导航 121 | - [ ] 自动寻路 (只限无迷雾地图) 122 | - [ ] 自动战斗 (不凹极限比 Auto 打的好就行) 123 | -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | ## 任务编写标准 4 | 5 | | 任务类型 | 任务名 | 任务内容 | 6 | | :----: | :----: | :----: | 7 | | Partial | + _Partial | 使用了多语言资源 | 8 | | Sub | Sub_ + | 子任务 | 9 | | Done | Done_ + | 任务链出口 | 10 | | Entry | 跟随自然语言 | 任务链入口 | 11 | | Start (≈Flag) | Start_EntryName / Start_跟随自然语言 | 某一实际业务入口 | 12 | | End | End_EntryName / End_跟随自然语言 | 某一实际业务出口 | 13 | | Goto | Goto_EntryName | 前往某一实际业务页面 | 14 | | Action | 动作类型_动作对象 [ _动作对象的对象 / _EntryName ] | 实际业务 | 15 | | Flag | 跟随自然语言 + Flag | 遇到 Flag 时结束 | 16 | 17 | ## 多语言支持 18 | 19 | 嘤嘤嘤,开发者不懂 `韩语` 和 `泰语`,如有需要,欢迎 pr。 20 | 21 | ### 相关指南 22 | 23 | `assets/Resource` 为 `MaaFramework` 使用的资源文件,其中 `BASE` 为各服务器、各语言的通用资源。 24 | 25 | 各区域资源文件夹以 `EN` 英语区域为基准,文件夹名分别是: 26 | - 日语: JP 27 | - 韩语: KR 28 | - 英语: EN (Base) 29 | - 泰语: TH 30 | - 繁体中文: TC 31 | - 简体中文: SC 32 | 33 | 如果要新建一个区域资源文件夹,需要包含 `image/` `pipeline/` `model/` `properties.json`。 34 | - image: 需要通过 `tools/CropRoi` 截图替换 35 | - pipeline: 需要修改 `OCRPartialTasks.json` 36 | - model: 需要添加 [OCR ONNX 模型](https://github.com/MaaAssistantArknights/MaaCommonAssets/tree/main/OCR) 37 | - properties.json (TODO): 需要设置 `"is_base": false, "version": "XX", "EN_version": "XX"` 38 | 39 | ## Multi-language support 40 | 41 | Developer (@Dissectum) totally doesn't understand Korean/KR (한국어) or Thai/TH (ภาษาไทย). Welcome to pull requests if you need it. 42 | 43 | ### Related Guidelines 44 | 45 | `assets/Resource` is the resource file used by `MaaFramework`, where `BASE` is the common resource for each server and each language. 46 | 47 | The resource folders for each region are based on the `EN` English region, and the folder names are as follows: 48 | - Japanese: JP 49 | - Korean: KR 50 | - English: EN (Base) 51 | - Thai: TH 52 | - Traditional Chinese: TC 53 | - Simplified Chinese: SC 54 | 55 | To create a new region resource folder, you need to include `image/` `pipeline/` `model/` `properties.json`. 56 | - image: need to be replaced by `tools/CropRoi` screenshot. 57 | - pipeline: need to modify `OCRPartialTasks.json`. 58 | - model: need to add [OCR ONNX model](https://github.com/MaaAssistantArknights/MaaCommonAssets/tree/main/OCR). 59 | - properties.json (TODO): need to set `"is_base": false, "version": "XX", "EN_version": "XX"` 60 | -------------------------------------------------------------------------------- /assets/Resource/Base/image/Arona.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Arona.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Buttons/Back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Buttons/Back.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Buttons/Close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Buttons/Close.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Buttons/CloseFullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Buttons/CloseFullscreen.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Buttons/Home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Buttons/Home.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Buttons/Pass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Buttons/Pass.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Buttons/Plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Buttons/Plus.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Buttons/ThreeStarsFlag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Buttons/ThreeStarsFlag.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Cafe/CloseSidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Cafe/CloseSidebar.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Cafe/StudentAffection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Cafe/StudentAffection.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Cafe/StudentAffection1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Cafe/StudentAffection1.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Cafe/StudentAffection2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Cafe/StudentAffection2.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Campaign/Campaign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Campaign/Campaign.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Mailbox/Mailbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Mailbox/Mailbox.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/TacticalChallenge/Pyroxene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/TacticalChallenge/Pyroxene.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/TacticalChallenge/ZeroTicket1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/TacticalChallenge/ZeroTicket1.png -------------------------------------------------------------------------------- /assets/Resource/Base/image/Tasks/Tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/image/Tasks/Tasks.png -------------------------------------------------------------------------------- /assets/Resource/Base/model/ocr/README.md: -------------------------------------------------------------------------------- 1 | # PaddleOCR model 2 | 3 | 2023/08/05 4 | 5 | from 6 | 7 | ## det model 8 | 9 | en_PP-OCRv3_det 10 | [New] Original lightweight detection model, supporting English 11 | 12 | 13 | 14 | ## rec model 15 | 16 | en_PP-OCRv3_rec 17 | [New] Original lightweight model, supporting English, English, multilingual text recognition 18 | 19 | 20 | 21 | ## rec label 22 | 23 | 24 | -------------------------------------------------------------------------------- /assets/Resource/Base/model/ocr/det.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/model/ocr/det.onnx -------------------------------------------------------------------------------- /assets/Resource/Base/model/ocr/keys.txt: -------------------------------------------------------------------------------- 1 | 0 2 | 1 3 | 2 4 | 3 5 | 4 6 | 5 7 | 6 8 | 7 9 | 8 10 | 9 11 | : 12 | ; 13 | < 14 | = 15 | > 16 | ? 17 | @ 18 | A 19 | B 20 | C 21 | D 22 | E 23 | F 24 | G 25 | H 26 | I 27 | J 28 | K 29 | L 30 | M 31 | N 32 | O 33 | P 34 | Q 35 | R 36 | S 37 | T 38 | U 39 | V 40 | W 41 | X 42 | Y 43 | Z 44 | [ 45 | \ 46 | ] 47 | ^ 48 | _ 49 | ` 50 | a 51 | b 52 | c 53 | d 54 | e 55 | f 56 | g 57 | h 58 | i 59 | j 60 | k 61 | l 62 | m 63 | n 64 | o 65 | p 66 | q 67 | r 68 | s 69 | t 70 | u 71 | v 72 | w 73 | x 74 | y 75 | z 76 | { 77 | | 78 | } 79 | ~ 80 | ! 81 | " 82 | # 83 | $ 84 | % 85 | & 86 | ' 87 | ( 88 | ) 89 | * 90 | + 91 | , 92 | - 93 | . 94 | / 95 | 96 | -------------------------------------------------------------------------------- /assets/Resource/Base/model/ocr/rec.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/Base/model/ocr/rec.onnx -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Bounty.json: -------------------------------------------------------------------------------- 1 | { 2 | "BountyGlobal": { 3 | "next": "StopOnException" 4 | }, 5 | "Overpass": { 6 | "next": [ 7 | "Sub_Wait_NowLoading_Partial", 8 | "Sub_Goto_Overpass_Partial", 9 | "Start_SweepMission_OnBounty" 10 | ] 11 | }, 12 | "DesertRailroad": { 13 | "next": [ 14 | "Sub_Wait_NowLoading_Partial", 15 | "Sub_Goto_DesertRailroad_Partial", 16 | "Start_SweepMission_OnBounty" 17 | ] 18 | }, 19 | "Classroom": { 20 | "next": [ 21 | "Sub_Wait_NowLoading_Partial", 22 | "Sub_Goto_Classroom_Partial", 23 | "Start_SweepMission_OnBounty" 24 | ] 25 | }, 26 | "Sub_Goto_Bounty_Partial": { 27 | "is_sub": true, 28 | "inverse": true, 29 | "recognition": "OCR", 30 | "text": "LocationSelect", 31 | "roi": [ 650, 75, 400, 60 ], 32 | "next": [ 33 | "Click_BountyButton_Partial", 34 | "BountyFlag_Partial", 35 | "Sub_Wait_NowLoading_Partial", 36 | "Sub_Goto_Campaign" 37 | ] 38 | }, 39 | "Click_BountyButton_Partial": { 40 | "recognition": "OCR", 41 | "text": "Bounty", 42 | "roi": [ 43 | [ 650, 390, 180, 125 ], 44 | [ 660, 390, 170, 75 ], 45 | [ 668, 407, 103, 33 ] 46 | ], 47 | "action": "Click", 48 | "post_delay": 1500 49 | }, 50 | "BountyFlag_Partial": { 51 | "recognition": "OCR", 52 | "text": "Bounty", 53 | "roi": [ 0, 0, 450, 60 ], 54 | "next": [ 55 | "Click_BackButton" 56 | ] 57 | }, 58 | "Start_SweepMission_OnBounty": { 59 | "next": [ 60 | "Start_SweepMission_Partial", 61 | "Sub_Click_EnterButton_OnClearedMission_Partial", 62 | "StopOnException" 63 | ] 64 | }, 65 | "Check_BountyTicket": { 66 | "skip_review": 4, 67 | "model": "../../../Base/model/ocr/", 68 | "recognition": "OCR", 69 | "text": [ "0/6", "0/", "0.?6" ], 70 | "roi": [ 35, 80, 240, 40 ], 71 | "next": "StopTask" 72 | }, 73 | "Sub_Goto_Overpass_Partial": { 74 | "is_sub": true, 75 | "inverse": true, 76 | "recognition": "OCR", 77 | "text": "Overpass", 78 | "roi": [ 90, 130, 530, 85 ], 79 | "next": [ 80 | "Check_BountyTicket", 81 | "Click_Overpass_Partial", 82 | "Sub_Wait_NowLoading_Partial", 83 | "Sub_Goto_Bounty_Partial" 84 | ] 85 | }, 86 | "Click_Overpass_Partial": { 87 | "recognition": "OCR", 88 | "text": "Overpass", 89 | "roi": [ 90 | [ 645, 140, 610, 475 ], 91 | [ 1090, 165, 134, 38 ] 92 | ], 93 | "action": "Click", 94 | "post_delay": 1500 95 | }, 96 | "Sub_Goto_DesertRailroad_Partial": { 97 | "is_sub": true, 98 | "inverse": true, 99 | "recognition": "OCR", 100 | "text": "DesertRailroad", 101 | "roi": [ 90, 130, 530, 85 ], 102 | "next": [ 103 | "Check_BountyTicket", 104 | "Click_DesertRailroad_Partial", 105 | "Sub_Wait_NowLoading_Partial", 106 | "Sub_Goto_Bounty_Partial" 107 | ] 108 | }, 109 | "Click_DesertRailroad_Partial": { 110 | "recognition": "OCR", 111 | "text": "DesertRailroad", 112 | "roi": [ 113 | [ 645, 140, 610, 475 ], 114 | [ 1032, 273, 192, 37 ] 115 | ], 116 | "action": "Click", 117 | "post_delay": 1500 118 | }, 119 | "Sub_Goto_Classroom_Partial": { 120 | "is_sub": true, 121 | "inverse": true, 122 | "recognition": "OCR", 123 | "text": "Classroom", 124 | "roi": [ 90, 130, 530, 85 ], 125 | "next": [ 126 | "Check_BountyTicket", 127 | "Click_Classroom_Partial", 128 | "Sub_Wait_NowLoading_Partial", 129 | "Sub_Goto_Bounty_Partial" 130 | ] 131 | }, 132 | "Click_Classroom_Partial": { 133 | "recognition": "OCR", 134 | "text": "Classroom", 135 | "roi": [ 136 | [ 645, 140, 610, 475 ], 137 | [ 1153, 379, 70, 37 ] 138 | ], 139 | "action": "Click", 140 | "post_delay": 1500 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Buttons.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sub_Click_HomeButton": { 3 | "skip_review": 6, 4 | "is_sub": true, 5 | "recognition": "TemplateMatch", 6 | "template": "../../Base/image/Buttons/Home.png", 7 | "roi": [ 1165, 0, 115, 138 ], 8 | "action": "Click", 9 | "post_delay": 1500 10 | }, 11 | "Sub_Click_BackButton": { 12 | "skip_review": 6, 13 | "is_sub": true, 14 | "recognition": "TemplateMatch", 15 | "template": "../../Base/image/Buttons/Back.png", 16 | "roi": [ 0, 0, 143, 140 ], 17 | "action": "Click", 18 | "post_delay": 1500 19 | }, 20 | "Click_BackButton": { 21 | "skip_review": 6, 22 | "recognition": "TemplateMatch", 23 | "template": "../../Base/image/Buttons/Back.png", 24 | "roi": [ 0, 0, 143, 140 ], 25 | "action": "Click", 26 | "post_delay": 1500 27 | }, 28 | "Sub_Click_CloseButton": { 29 | "skip_review": 6, 30 | "is_sub": true, 31 | "recognition": "TemplateMatch", 32 | "template": "../../Base/image/Buttons/Close.png", 33 | "roi": [ 34 | [ 1113, 52, 131, 131 ], 35 | [ 857, 123, 131, 131 ], 36 | [ 822, 97, 131, 131 ], 37 | [ 880, 145, 80, 80 ], 38 | [ 972, 58, 80, 80 ] 39 | ], 40 | "action": "Click", 41 | "post_delay": 1500 42 | }, 43 | "Sub_Click_PassButton": { 44 | "skip_review": 6, 45 | "is_sub": true, 46 | "recognition": "TemplateMatch", 47 | "template": "../../Base/image/Buttons/Pass.png", 48 | "roi": [ 1167, 0, 113, 139 ], 49 | "action": "Click", 50 | "post_delay": 1500 51 | }, 52 | "Sub_Click_CloseFullscreenButton": { 53 | "skip_review": 6, 54 | "is_sub": true, 55 | "recognition": "TemplateMatch", 56 | "template": "../../Base/image/Buttons/CloseFullscreen.png", 57 | "roi": [ 1145, 0, 135, 145 ], 58 | "action": "Click", 59 | "post_delay": 1500 60 | }, 61 | "Click_TouchButton_Partial": { 62 | "recognition": "OCR", 63 | "text": "TOUCH", 64 | "roi": [ 525, 570, 228, 124 ], 65 | "action": "Click" 66 | }, 67 | "Start_SweepMission_Partial": { 68 | "recognition": "OCR", 69 | "text": "MissionInfo", 70 | "roi": [ 496, 76, 290, 129 ], 71 | "next": [ 72 | "Click_MaxButton", 73 | "Click_PlusButton" 74 | ] 75 | }, 76 | "Click_PlusButton": { 77 | "skip_review": 6, 78 | "doc": "times_limit setted in code", 79 | "recognition": "TemplateMatch", 80 | "template": "../../Base/image/Buttons/Plus.png", 81 | "threshold": 0.8, 82 | "roi": [ 83 | [ 970, 255, 90, 90 ] 84 | ], 85 | "action": "Click", 86 | "next": [ 87 | "Click_PlusButton", 88 | "Stop_Sweep_OnZeroTimes", 89 | "Click_StartSweepButton_Partial" 90 | ], 91 | "runout_next": [ 92 | "Stop_Sweep_OnZeroTimes", 93 | "Click_StartSweepButton_Partial" 94 | ] 95 | }, 96 | "Click_MaxButton": { 97 | "skip_review": 4, 98 | "doc": "enabled setted in code", 99 | "enabled": false, 100 | "model": "../../../Base/model/ocr/", 101 | "recognition": "OCR", 102 | "text": "Max", 103 | "roi": [ 104 | [ 740, 200, 395, 260 ] 105 | ], 106 | "action": "Click", 107 | "next": [ 108 | "Stop_Sweep_OnZeroTimes", 109 | "Click_StartSweepButton_Partial" 110 | ] 111 | }, 112 | "Stop_Sweep_OnZeroTimes": { 113 | "skip_review": 4, 114 | "model": "../../../Base/model/ocr/", 115 | "recognition": "OCR", 116 | "text": "0", 117 | "roi": [ 881, 279, 113, 43 ] 118 | }, 119 | "Click_StartSweepButton_Partial": { 120 | "recognition": "OCR", 121 | "text": "StartSweep", 122 | "roi": [ 806, 343, 261, 131 ], 123 | "action": "Click", 124 | "next": [ 125 | "Notice_Click_ConfirmButton_OnSweeping_Partial" 126 | ] 127 | }, 128 | "Notice_Click_ConfirmButton_OnSweeping_Partial": { 129 | "recognition": "OCR", 130 | "text": "Confirm", 131 | "roi": [ 360, 135, 560, 440 ], 132 | "action": "Click", 133 | "next": [ 134 | "Click_SkipButton_Partial", 135 | "Click_ConfirmButton_OnSweeped_Partial" 136 | ] 137 | }, 138 | "Click_SkipButton_Partial": { 139 | "recognition": "OCR", 140 | "text": "Skip", 141 | "roi": [ 535, 472, 213, 74 ], 142 | "target": [ 535, 472, 213, 74 ], 143 | "action": "Click", 144 | "next": [ 145 | "Click_ConfirmButton_OnSweeped_Partial" 146 | ] 147 | }, 148 | "Click_ConfirmButton_OnSweeped_Partial": { 149 | "recognition": "OCR", 150 | "text": "Confirm", 151 | "roi": [ 535, 547, 213, 74 ], 152 | "target": [ 535, 547, 213, 74 ], 153 | "action": "Click", 154 | "post_delay": 1500 155 | }, 156 | "Sub_Click_EnterButton_OnClearedMission_Partial": { 157 | "is_sub": true, 158 | "recognition": "OCR", 159 | "text": "Enter", 160 | "roi": [ 1040, 80, 155, 620 ], 161 | "next": [ 162 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag1", 163 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag2", 164 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag3", 165 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag4", 166 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag5", 167 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag6", 168 | "Sub_UpSwipe_OnClearedMission_Partial", 169 | "Stop" 170 | ] 171 | }, 172 | "Sub_UpSwipe_OnClearedMission_Partial": { 173 | "is_sub": false, 174 | "action": "Swipe", 175 | "end": [ 665, 555, 110, 130 ], 176 | "begin": [ 665, 130, 110, 130 ], 177 | "next": [ 178 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag1", 179 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag2", 180 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag3", 181 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag4", 182 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag5", 183 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag6", 184 | "Stop" 185 | ], 186 | "post_delay": 1500 187 | }, 188 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag1": { 189 | "skip_review": 6, 190 | "recognition": "TemplateMatch", 191 | "template": "../../Base/image/Buttons/ThreeStarsFlag.png", 192 | "threshold": 0.8, 193 | "roi": [ 665, 555, 110, 130 ], 194 | "target_offset": [ 375, 0, 35, -5 ], 195 | "action": "Click" 196 | }, 197 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag2": { 198 | "skip_review": 6, 199 | "recognition": "TemplateMatch", 200 | "template": "../../Base/image/Buttons/ThreeStarsFlag.png", 201 | "threshold": 0.8, 202 | "roi": [ 665, 470, 110, 130 ], 203 | "target_offset": [ 375, 0, 35, -5 ], 204 | "action": "Click" 205 | }, 206 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag3": { 207 | "skip_review": 6, 208 | "recognition": "TemplateMatch", 209 | "template": "../../Base/image/Buttons/ThreeStarsFlag.png", 210 | "threshold": 0.8, 211 | "roi": [ 665, 385, 110, 130 ], 212 | "target_offset": [ 375, 0, 35, -5 ], 213 | "action": "Click" 214 | }, 215 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag4": { 216 | "skip_review": 6, 217 | "recognition": "TemplateMatch", 218 | "template": "../../Base/image/Buttons/ThreeStarsFlag.png", 219 | "threshold": 0.8, 220 | "roi": [ 665, 300, 110, 130 ], 221 | "target_offset": [ 375, 0, 35, -5 ], 222 | "action": "Click" 223 | }, 224 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag5": { 225 | "skip_review": 6, 226 | "recognition": "TemplateMatch", 227 | "template": "../../Base/image/Buttons/ThreeStarsFlag.png", 228 | "threshold": 0.8, 229 | "roi": [ 665, 215, 110, 130 ], 230 | "target_offset": [ 375, 0, 35, -5 ], 231 | "action": "Click" 232 | }, 233 | "Click_EnterButton_OnTheRightSideOfThreeStarsFlag6": { 234 | "skip_review": 6, 235 | "recognition": "TemplateMatch", 236 | "template": "../../Base/image/Buttons/ThreeStarsFlag.png", 237 | "threshold": 0.8, 238 | "roi": [ 665, 130, 110, 130 ], 239 | "target_offset": [ 375, 0, 35, -5 ], 240 | "action": "Click" 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Cafe.json: -------------------------------------------------------------------------------- 1 | { 2 | "Cafe": { 3 | "next": [ 4 | "Sub_Wait_NowLoading_Partial", 5 | "Sub_Goto_Cafe_Partial", 6 | "Sub_CloseSidebar", 7 | "Sub_Click_CloseButton", 8 | "Sub_Click_StudentAffection", 9 | "Sub_Click_InvitationButton_Partial", 10 | "End_Cafe" 11 | ] 12 | }, 13 | "Sub_Goto_Cafe_Partial": { 14 | "is_sub": true, 15 | "inverse": true, 16 | "recognition": "OCR", 17 | "text": "Cafe", 18 | "roi": [ 0, 0, 450, 60 ], 19 | "next": [ 20 | "Click_CafeButton_Partial", 21 | "Sub_Wait_NowLoading_Partial", 22 | "Sub_Goto_Home" 23 | ] 24 | }, 25 | "Click_CafeButton_Partial": { 26 | "recognition": "OCR", 27 | "text": "Cafe", 28 | "roi": [ 23, 627, 144, 93 ], 29 | "action": "Click", 30 | "post_delay": 2500 31 | }, 32 | "Sub_CloseSidebar": { 33 | "skip_review": 6, 34 | "is_sub": true, 35 | "recognition": "TemplateMatch", 36 | "template": "../../Base/image/Cafe/CloseSidebar.png", 37 | "roi": [ 500, 570, 100, 100 ], 38 | "action": "Click" 39 | }, 40 | "End_Cafe": { 41 | "skip_review": 6, 42 | "inverse": true, 43 | "recognition": "TemplateMatch", 44 | "template": [ 45 | "../../Base/image/Cafe/StudentAffection.png", 46 | "../../Base/image/Cafe/StudentAffection1.png", 47 | "../../Base/image/Cafe/StudentAffection2.png" 48 | ], 49 | "green_mask": true, 50 | "threshold": [ 51 | 0.55, 52 | 0.55, 53 | 0.55 54 | ], 55 | "next": [ 56 | "Sub_Click_CloseButton", 57 | "Sub_Click_StudentAffection", 58 | "Sub_Click_InvitationButton_Partial", 59 | "Sub_Click_CafeEarningsButton_Partial", 60 | "Click_ComfortButton_Partial", 61 | "Stop" 62 | ] 63 | }, 64 | "Sub_Click_StudentAffection": { 65 | "skip_review": 6, 66 | "is_sub": true, 67 | "recognition": "TemplateMatch", 68 | "template": [ 69 | "../../Base/image/Cafe/StudentAffection.png", 70 | "../../Base/image/Cafe/StudentAffection1.png", 71 | "../../Base/image/Cafe/StudentAffection2.png" 72 | ], 73 | "green_mask": true, 74 | "threshold": [ 75 | 0.55, 76 | 0.55, 77 | 0.55 78 | ], 79 | "target_offset": [ 50, 40, 0, 0 ], 80 | "action": "Click", 81 | "post_wait_freezes": { 82 | "time": 2000, 83 | "target": [ 0, 660, 1280, 60 ] 84 | }, 85 | "next": [ 86 | "Sub_Check_RelationshipRankUp_Partial", 87 | "Stop" 88 | ] 89 | }, 90 | "Sub_Check_RelationshipRankUp_Partial": { 91 | "is_sub": true, 92 | "inverse": true, 93 | "times_limit": 10, 94 | "recognition": "OCR", 95 | "text": "Until Next Visit", 96 | "roi": [ 35, 80, 270, 40 ], 97 | "target": [ 35, 80, 270, 40 ], 98 | "action": "Click", 99 | "runout_next": [ 100 | "StopOnException" 101 | ] 102 | }, 103 | "Sub_Click_InvitationButton_Partial": { 104 | "is_sub": true, 105 | "recognition": "OCR", 106 | "text": "Available", 107 | "roi": [ 687, 538, 229, 117 ], 108 | "target": [ 793, 619, 73, 79 ], 109 | "action": "Click", 110 | "next": [ 111 | "Click_InviteButton_Partial", 112 | "Click_InvitationButton_Partial", 113 | "Stop" 114 | ] 115 | }, 116 | "Click_InvitationButton_Partial": { 117 | "recognition": "OCR", 118 | "text": "Available", 119 | "roi": [ 687, 538, 229, 117 ], 120 | "target": [ 793, 619, 73, 79 ], 121 | "action": "Click", 122 | "next": [ 123 | "Click_InviteButton_Partial", 124 | "Click_InvitationButton_Partial", 125 | "Stop" 126 | ] 127 | }, 128 | "Click_InviteButton_Partial": { 129 | "recognition": "OCR", 130 | "text": "Invite", 131 | "roi": [ 417, 187, 437, 79 ], 132 | "action": "Click", 133 | "next": [ 134 | "Notice_Click_ConfirmButton_OnInviting_Partial" 135 | ] 136 | }, 137 | "Notice_Click_ConfirmButton_OnInviting_Partial": { 138 | "recognition": "OCR", 139 | "text": "Confirm", 140 | "roi": [ 360, 135, 560, 440 ], 141 | "action": "Click", 142 | "post_wait_freezes": 1500 143 | }, 144 | "Sub_Click_CafeEarningsButton_Partial": { 145 | "is_sub": true, 146 | "recognition": "OCR", 147 | "text": "Available", 148 | "roi": [ 1027, 520, 253, 120 ], 149 | "target": [ 1079, 606, 152, 79 ], 150 | "action": "Click", 151 | "next": [ 152 | "Click_ClaimButton_ForCafeEarnings_Partial", 153 | "Click_CafeEarningsButton_Partial", 154 | "Stop" 155 | ] 156 | }, 157 | "Click_CafeEarningsButton_Partial": { 158 | "recognition": "OCR", 159 | "text": "Available", 160 | "roi": [ 1027, 520, 253, 120 ], 161 | "target": [ 1079, 606, 152, 79 ], 162 | "action": "Click", 163 | "next": [ 164 | "Click_ClaimButton_ForCafeEarnings_Partial", 165 | "Click_CafeEarningsButton_Partial", 166 | "Stop" 167 | ] 168 | }, 169 | "Click_ClaimButton_ForCafeEarnings_Partial": { 170 | "recognition": "OCR", 171 | "text": "Claim", 172 | "roi": [ 535, 484, 210, 73 ], 173 | "target": [ 535, 484, 210, 73 ], 174 | "action": "Click", 175 | "post_delay": 1000, 176 | "next": [ 177 | "Click_TouchButton_Partial" 178 | ], 179 | "timeout": 5000 180 | }, 181 | "Click_ComfortButton_Partial": { 182 | "recognition": "OCR", 183 | "text": "Comfort", 184 | "roi": [ 903, 607, 151, 80 ], 185 | "target": [ 903, 607, 151, 80 ], 186 | "action": "Click", 187 | "next": [ 188 | "Click_RankUpButton_OnCafeInfo_Partial" 189 | ] 190 | }, 191 | "Click_RankUpButton_OnCafeInfo_Partial": { 192 | "recognition": "OCR", 193 | "text": "RankUp", 194 | "roi": [ 533, 498, 215, 71 ], 195 | "target": [ 533, 498, 215, 71 ], 196 | "action": "Click", 197 | "next": [ 198 | "Click_RankUpButton_OnCafeRankUp_Partial" 199 | ] 200 | }, 201 | "Click_RankUpButton_OnCafeRankUp_Partial": { 202 | "recognition": "OCR", 203 | "text": "RankUp", 204 | "roi": [ 746, 517, 227, 137 ], 205 | "action": "Click" 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Campaign.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sub_Goto_Campaign": { 3 | "is_sub": true, 4 | "next": [ 5 | "CampaignFlag_Partial", 6 | "Sub_Wait_NowLoading_Partial", 7 | "Click_Campaign", 8 | "Sub_Goto_Home" 9 | ] 10 | }, 11 | "CampaignFlag_Partial": { 12 | "recognition": "OCR", 13 | "text": "Campaign", 14 | "roi": [ 0, 0, 450, 60 ] 15 | }, 16 | "Click_Campaign": { 17 | "skip_review": 6, 18 | "recognition": "TemplateMatch", 19 | "template": "../../Base/image/Campaign/Campaign.png", 20 | "roi": [ 1087, 478, 193, 147 ], 21 | "action": "Click", 22 | "post_delay": 1500 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Club.json: -------------------------------------------------------------------------------- 1 | { 2 | "Club": { 3 | "next": [ 4 | "Sub_Wait_NowLoading_Partial", 5 | "Sub_Goto_Club_Partial", 6 | "Stop" 7 | ] 8 | }, 9 | "Sub_Goto_Club_Partial": { 10 | "doc": "这个 json 同时是前往一个位置的最小单元实例,NowLoading 需要和 Goto 的父级绑定(TODO:每次出现场景变化的时候均为使用 Goto 之后,同个场景的任务尽可能使用 Sub 并列)(需要更改的文件有 Buttons Campaign Mailbox StartUp TacticalChallenge)。非业务类的弹窗则尽可能由 ProcessingNotice 处理", 11 | "is_sub": true, 12 | "inverse": true, 13 | "recognition": "OCR", 14 | "text": "Club", 15 | "roi": [ 0, 0, 450, 60 ], 16 | "next": [ 17 | "Click_ClubButton_Partial", 18 | "Sub_Wait_NowLoading_Partial", 19 | "Sub_Goto_Home" 20 | ] 21 | }, 22 | "Click_ClubButton_Partial": { 23 | "recognition": "OCR", 24 | "text": "Club", 25 | "roi": [ 493, 628, 139, 92 ], 26 | "action": "Click", 27 | "post_delay": 1500 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Commissions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Commissions": { 3 | "next": "StopOnException" 4 | }, 5 | "BaseDefense": { 6 | "next": [ 7 | "Sub_Wait_NowLoading_Partial", 8 | "Sub_Goto_BaseDefense_Partial", 9 | "Start_SweepMission_OnCommissions" 10 | ] 11 | }, 12 | "ItemRetrieval": { 13 | "next": [ 14 | "Sub_Wait_NowLoading_Partial", 15 | "Sub_Goto_ItemRetrieval_Partial", 16 | "Start_SweepMission_OnCommissions" 17 | ] 18 | }, 19 | "Sub_Goto_Commissions_Partial": { 20 | "is_sub": true, 21 | "inverse": true, 22 | "recognition": "OCR", 23 | "text": "RequestSelect", 24 | "roi": [ 650, 75, 400, 60 ], 25 | "next": [ 26 | "Click_CommissionsButton_Partial", 27 | "CommissionsFlag_Partial", 28 | "Sub_Wait_NowLoading_Partial", 29 | "Sub_Goto_Campaign" 30 | ] 31 | }, 32 | "Sub_Goto_BaseDefense_Partial": { 33 | "is_sub": true, 34 | "inverse": true, 35 | "recognition": "OCR", 36 | "text": "BaseDefense", 37 | "roi": [ 90, 130, 530, 60 ], 38 | "next": [ 39 | "Click_BaseDefense_Partial", 40 | "Sub_Wait_NowLoading_Partial", 41 | "Sub_Goto_Commissions_Partial" 42 | ] 43 | }, 44 | "Sub_Goto_ItemRetrieval_Partial": { 45 | "is_sub": true, 46 | "inverse": true, 47 | "recognition": "OCR", 48 | "text": "ItemRetrieval", 49 | "roi": [ 90, 130, 530, 60 ], 50 | "next": [ 51 | "Click_ItemRetrieval_Partial", 52 | "Sub_Wait_NowLoading_Partial", 53 | "Sub_Goto_Commissions_Partial" 54 | ] 55 | }, 56 | "CommissionsFlag_Partial": { 57 | "recognition": "OCR", 58 | "text": "Commissions", 59 | "roi": [ 0, 0, 450, 60 ], 60 | "next": [ 61 | "Click_BackButton" 62 | ] 63 | }, 64 | "Click_CommissionsButton_Partial": { 65 | "recognition": "OCR", 66 | "text": "Commissions", 67 | "roi": [ 580, 420, 290, 260 ], 68 | "action": "Click", 69 | "post_delay": 1500 70 | }, 71 | "Click_BaseDefense_Partial": { 72 | "recognition": "OCR", 73 | "text": "BaseDefense", 74 | "roi": [ 75 | [ 645, 140, 610, 475 ], 76 | [ 1090, 165, 135, 38 ] 77 | ], 78 | "action": "Click", 79 | "post_delay": 1500 80 | }, 81 | "Click_ItemRetrieval_Partial": { 82 | "recognition": "OCR", 83 | "text": "ItemRetrieval", 84 | "roi": [ 85 | [ 645, 140, 610, 475 ], 86 | [ 1031, 273, 193, 37 ] 87 | ], 88 | "action": "Click", 89 | "post_delay": 1500 90 | }, 91 | "Start_SweepMission_OnCommissions": { 92 | "next": [ 93 | "Start_SweepMission_Partial", 94 | "Sub_Click_EnterButton_OnClearedMission_Partial", 95 | "StopOnException" 96 | ] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Crafting.json: -------------------------------------------------------------------------------- 1 | { 2 | "Crafting": { 3 | "TODO": "需要判断颜色 + 遍历所有可选项,还有撤销 skip_review", 4 | "next": [ 5 | "Sub_Wait_NowLoading_Partial", 6 | "Sub_Goto_MaterialSynthesis_Partial", 7 | "Sub_Click_Receive", 8 | "Sub_Start_MaterialSynthesis", 9 | "Start_MaterialFusion", 10 | "Stop" 11 | ] 12 | }, 13 | "Sub_Goto_Crafting": { 14 | "skip_review": 4, 15 | "is_sub": true, 16 | "inverse": true, 17 | "recognition": "OCR", 18 | "text": "Crafting", 19 | "roi": [ 0, 0, 450, 60 ], 20 | "next": [ 21 | "Click_CraftingButton", 22 | "Sub_Wait_NowLoading_Partial", 23 | "Sub_Goto_Home" 24 | ] 25 | }, 26 | "Click_CraftingButton": { 27 | "skip_review": 4, 28 | "recognition": "OCR", 29 | "text": "Crafting", 30 | "roi": [ 594, 628, 170, 92 ], 31 | "action": "Click", 32 | "post_delay": 1500 33 | }, 34 | "Sub_Click_Receive": { 35 | "skip_review": 4, 36 | "is_sub": true, 37 | "recognition": "OCR", 38 | "text": "Receive", 39 | "roi": [ 671, 216, 565, 413 ], 40 | "action": "Click", 41 | "next": [ 42 | "Click_TouchButton_Partial" 43 | ], 44 | "timeout": 5000 45 | }, 46 | "Sub_Start_MaterialSynthesis": { 47 | "skip_review": 4, 48 | "is_sub": true, 49 | "recognition": "OCR", 50 | "text": "StartCrafting", 51 | "roi": [ 671, 216, 565, 413 ], 52 | "action": "Click", 53 | "post_delay": 1500, 54 | "next": [ 55 | "Sub_Click_KeystoneButton" 56 | ], 57 | "timeout": 5000 58 | }, 59 | "Start_MaterialFusion": { 60 | "enabled": false, 61 | "next": [ 62 | "Sub_Wait_NowLoading_Partial", 63 | "Sub_Goto_MaterialSynthesis_Partial", 64 | "Sub_Click_Receive", 65 | "TODO" 66 | ] 67 | }, 68 | "Sub_Goto_MaterialSynthesis_Partial": { 69 | "skip_review": 6, 70 | "is_sub": true, 71 | "inverse": true, 72 | "recognition": "TemplateMatch", 73 | "template": "Arona.png", 74 | "next": [ 75 | "Click_MaterialSynthesis_Partial", 76 | "Sub_Notice_Partial", 77 | "Sub_Wait_NowLoading_Partial", 78 | "Sub_Goto_Crafting" 79 | ] 80 | }, 81 | "Sub_Goto_MaterialFusion_Partial": { 82 | "skip_review": 6, 83 | "is_sub": true, 84 | "inverse": true, 85 | "recognition": "TemplateMatch", 86 | "template": "Arona.png", 87 | "next": [ 88 | "Click_MaterialFusion_Partial", 89 | "Sub_Wait_NowLoading_Partial", 90 | "Sub_Goto_Crafting" 91 | ] 92 | }, 93 | "Click_MaterialSynthesis_Partial": { 94 | "recognition": "TemplateMatch", 95 | "template": "Arona.png", 96 | "roi": [ 0, 105, 285, 165 ], 97 | "action": "Click" 98 | }, 99 | "Click_MaterialFusion_Partial": { 100 | "recognition": "TemplateMatch", 101 | "template": "Arona.png", 102 | "roi": [ 0, 185, 285, 165 ], 103 | "action": "Click" 104 | }, 105 | "Sub_Click_KeystoneButton": { 106 | "is_sub": true 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Mailbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "Mailbox": { 3 | "next": [ 4 | "Sub_Wait_NowLoading_Partial", 5 | "Sub_Goto_Mailbox_Partial", 6 | "NoMoreMailFlag_Partial", 7 | "Click_ClaimAllButton_Mailbox_Partial" 8 | ] 9 | }, 10 | "Sub_Goto_Mailbox_Partial": { 11 | "is_sub": true, 12 | "inverse": true, 13 | "recognition": "OCR", 14 | "text": "Mailbox", 15 | "roi": [ 0, 0, 450, 60 ], 16 | "next": [ 17 | "Click_MailboxButton", 18 | "Sub_Wait_NowLoading_Partial", 19 | "Sub_Goto_Home" 20 | ] 21 | }, 22 | "Click_MailboxButton": { 23 | "skip_review": 6, 24 | "recognition": "TemplateMatch", 25 | "template": "../../Base/image/Mailbox/Mailbox.png", 26 | "roi": [ 1077, 0, 131, 126 ], 27 | "action": "Click", 28 | "post_delay": 1500 29 | }, 30 | "NoMoreMailFlag_Partial": { 31 | "recognition": "OCR", 32 | "text": "NoMoreMail", 33 | "roi": [ 621, 427, 295, 131 ] 34 | }, 35 | "Click_ClaimAllButton_Mailbox_Partial": { 36 | "TODO": "顏色識別", 37 | "recognition": "OCR", 38 | "text": "ClaimAll", 39 | "roi": [ 1038, 641, 193, 62 ], 40 | "target": [ 1038, 641, 193, 62 ], 41 | "action": "Click", 42 | "next": [ 43 | "Click_TouchButton_Partial" 44 | ], 45 | "timeout": 5000 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/ProcessingNotice.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sub_Notice_Partial": { 3 | "is_sub": true, 4 | "recognition": "OCR", 5 | "text": "Notice", 6 | "roi": [ 360, 135, 560, 440 ], 7 | "next": [ 8 | "Sub_Notice_Quit_Partial", 9 | "Notice_Unknown" 10 | ] 11 | }, 12 | "Notice_Click_CancelButton_Partial": { 13 | "recognition": "OCR", 14 | "text": "Cancel", 15 | "roi": [ 360, 135, 560, 440 ], 16 | "action": "Click" 17 | }, 18 | "Notice_Click_ConfirmButton_Partial": { 19 | "recognition": "OCR", 20 | "text": "Confirm", 21 | "roi": [ 360, 135, 560, 440 ], 22 | "action": "Click" 23 | }, 24 | "Notice_Unknown": { 25 | "TODO": "回调通知", 26 | "next": [ 27 | "StopOnException" 28 | ] 29 | }, 30 | "Sub_Notice_Quit_Partial": { 31 | "is_sub": true, 32 | "recognition": "OCR", 33 | "text": "Quit?", 34 | "roi": [ 360, 135, 560, 440 ], 35 | "next": [ 36 | "Notice_Click_CancelButton_Partial" 37 | ] 38 | }, 39 | "note1": { 40 | "text": "The roi (1920*1080) of a Notice MessageBox is", 41 | "roi": [ 360, 135, 560, 440 ] 42 | }, 43 | "note2": { 44 | "text": "The roi (1920*1080) of a title flag is", 45 | "roi": [ 0, 0, 450, 60 ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Scrimmage.json: -------------------------------------------------------------------------------- 1 | { 2 | "ScrimmageGlobal": { 3 | "next": "StopOnException" 4 | }, 5 | "Trinity": { 6 | "next": [ 7 | "Sub_Wait_NowLoading_Partial", 8 | "Sub_Goto_Trinity_Partial", 9 | "Start_SweepMission_OnScrimmage" 10 | ] 11 | }, 12 | "Gehenna": { 13 | "next": [ 14 | "Sub_Wait_NowLoading_Partial", 15 | "Sub_Goto_Gehenna_Partial", 16 | "Start_SweepMission_OnScrimmage" 17 | ] 18 | }, 19 | "Millennium": { 20 | "next": [ 21 | "Sub_Wait_NowLoading_Partial", 22 | "Sub_Goto_Millennium_Partial", 23 | "Start_SweepMission_OnScrimmage" 24 | ] 25 | }, 26 | "Sub_Goto_Scrimmage_Partial": { 27 | "is_sub": true, 28 | "inverse": true, 29 | "recognition": "OCR", 30 | "text": "AcademySelect", 31 | "roi": [ 650, 75, 400, 60 ], 32 | "next": [ 33 | "Click_ScrimmageButton_Partial", 34 | "ScrimmageFlag_Partial", 35 | "Sub_Wait_NowLoading_Partial", 36 | "Sub_Goto_Campaign" 37 | ] 38 | }, 39 | "Click_ScrimmageButton_Partial": { 40 | "recognition": "OCR", 41 | "text": "Scrimmage", 42 | "roi": [ 636, 558, 160, 70 ], 43 | "action": "Click", 44 | "post_delay": 1500 45 | }, 46 | "ScrimmageFlag_Partial": { 47 | "recognition": "OCR", 48 | "text": "Scrimmage", 49 | "roi": [ 0, 0, 450, 60 ], 50 | "next": [ 51 | "Click_BackButton" 52 | ] 53 | }, 54 | "Start_SweepMission_OnScrimmage": { 55 | "next": [ 56 | "Start_SweepMission_Partial", 57 | "Sub_Click_EnterButton_OnClearedMission_Partial", 58 | "StopOnException" 59 | ] 60 | }, 61 | "Check_ScrimmageTicket": { 62 | "skip_review": 4, 63 | "model": "../../../Base/model/ocr/", 64 | "recognition": "OCR", 65 | "text": [ "0/6", "0/", "0.?6" ], 66 | "roi": [ 35, 80, 240, 40 ], 67 | "next": "StopTask" 68 | }, 69 | "Sub_Goto_Trinity_Partial": { 70 | "is_sub": true, 71 | "inverse": true, 72 | "recognition": "OCR", 73 | "text": "Trinity", 74 | "roi": [ 90, 130, 530, 85 ], 75 | "next": [ 76 | "Check_ScrimmageTicket", 77 | "Click_Trinity_Partial", 78 | "Sub_Wait_NowLoading_Partial", 79 | "Sub_Goto_Scrimmage_Partial" 80 | ] 81 | }, 82 | "Click_Trinity_Partial": { 83 | "recognition": "OCR", 84 | "text": "Trinity", 85 | "roi": [ 86 | [ 645, 140, 610, 475 ], 87 | [ 1102, 108, 168, 140 ], 88 | [ 1151, 166, 71, 36 ] 89 | ], 90 | "action": "Click", 91 | "post_delay": 1500 92 | }, 93 | "Sub_Goto_Gehenna_Partial": { 94 | "is_sub": true, 95 | "inverse": true, 96 | "recognition": "OCR", 97 | "text": "Gehenna", 98 | "roi": [ 90, 130, 530, 85 ], 99 | "next": [ 100 | "Check_ScrimmageTicket", 101 | "Click_Gehenna_Partial", 102 | "Sub_Wait_NowLoading_Partial", 103 | "Sub_Goto_Scrimmage_Partial" 104 | ] 105 | }, 106 | "Click_Gehenna_Partial": { 107 | "recognition": "OCR", 108 | "text": "Gehenna", 109 | "roi": [ 110 | [ 645, 140, 610, 475 ], 111 | [ 1122, 272, 102, 37 ] 112 | ], 113 | "action": "Click", 114 | "post_delay": 1500 115 | }, 116 | "Sub_Goto_Millennium_Partial": { 117 | "is_sub": true, 118 | "inverse": true, 119 | "recognition": "OCR", 120 | "text": "Millennium", 121 | "roi": [ 122 | [ 90, 130, 530, 85 ], 123 | [ 1155, 380, 67, 36 ] 124 | ], 125 | "next": [ 126 | "Check_ScrimmageTicket", 127 | "Click_Millennium_Partial", 128 | "Sub_Wait_NowLoading_Partial", 129 | "Sub_Goto_Scrimmage_Partial" 130 | ] 131 | }, 132 | "Click_Millennium_Partial": { 133 | "recognition": "OCR", 134 | "text": "Millennium", 135 | "roi": [ 645, 140, 610, 475 ], 136 | "action": "Click", 137 | "post_delay": 1500 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Shop.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/StartUp.json: -------------------------------------------------------------------------------- 1 | { 2 | "StartUp": { 3 | "action": "StartApp", 4 | "next": [ 5 | "HomeFlag", 6 | "Sub_Wait_NowLoading_Partial", 7 | "Sub_Goto_Home" 8 | ] 9 | }, 10 | "Sub_Goto_Home": { 11 | "is_sub": true, 12 | "next": [ 13 | "HomeFlag", 14 | "Sub_Wait_NowLoading_Partial", 15 | "Sub_Click_HomeButton", 16 | "Sub_Notice_Partial", 17 | "Sub_Click_BackButton", 18 | "Sub_Click_CloseButton", 19 | "Sub_Click_CloseFullscreenButton", 20 | "Sub_Click_SignIn_Partial", 21 | "Sub_StartApp" 22 | ] 23 | }, 24 | "HomeFlag": { 25 | "skip_review": 6, 26 | "recognition": "TemplateMatch", 27 | "template": "../../Base/image/Campaign/Campaign.png", 28 | "roi": [ 1086, 479, 194, 146 ] 29 | }, 30 | "Sub_StartApp": { 31 | "is_sub": true, 32 | "action": "StartApp", 33 | "next": [ 34 | "HomeFlag", 35 | "MenuFlag_Partial", 36 | "KeyBack_StartApp_Information" 37 | ] 38 | }, 39 | "MenuFlag_Partial": { 40 | "recognition": "OCR", 41 | "text": "Memu", 42 | "roi": [ 0, 570, 161, 135 ], 43 | "next": "ClickAndWait_AppLoading", 44 | "times_limit": 4, 45 | "runout_next": [ 46 | "StopTaskOnException" 47 | ] 48 | }, 49 | "ClickAndWait_AppLoading": { 50 | "action": "Click", 51 | "target": [ 0, 0, 1280, 700 ], 52 | "post_wait_freezes": { 53 | "time": 200, 54 | "target": [ 363, 136, 553, 437 ] 55 | } 56 | }, 57 | "KeyBack_StartApp_Information": { 58 | "action": "Key", 59 | "key": 4, 60 | "post_delay": 5000, 61 | "times_limit": 20, 62 | "runout_next": [ 63 | "StopTaskOnException" 64 | ] 65 | }, 66 | "Sub_Click_SignIn_Partial": { 67 | "is_sub": true, 68 | "recognition": "OCR", 69 | "text": "SignIn", 70 | "action": "Click", 71 | "roi": [ 488, 174, 725, 266 ], 72 | "target": [ 488, 174, 725, 266 ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/TacticalChallenge.json: -------------------------------------------------------------------------------- 1 | { 2 | "TacticalChallenge": { 3 | "next": [ 4 | "Sub_Start_TacticalChallenge_Partial", 5 | "Sub_Wait_NowLoading_Partial", 6 | "Sub_Goto_TacticalChallenge_Partial" 7 | ] 8 | }, 9 | "TacticalChallenge0": { 10 | "times_limit": 1, 11 | "next": [ 12 | "Click_ClaimButton_ForCreditPoints_Partial", 13 | "Sub_Wait_NowLoading_Partial", 14 | "Sub_Goto_TacticalChallenge_Partial" 15 | ], 16 | "runout_next": [ 17 | "StopTask" 18 | ] 19 | }, 20 | "Sub_Goto_TacticalChallenge_Partial": { 21 | "is_sub": true, 22 | "inverse": true, 23 | "recognition": "OCR", 24 | "text": "TacticalChallenge", 25 | "roi": [ 0, 0, 450, 60 ], 26 | "next": [ 27 | "Click_TacticalChallenge_Partial", 28 | "Sub_Wait_NowLoading_Partial", 29 | "Sub_Goto_Campaign" 30 | ] 31 | }, 32 | "Click_TacticalChallenge_Partial": { 33 | "recognition": "OCR", 34 | "text": "TacticalChallenge", 35 | "roi": [ 36 | [ 1031, 397, 155, 87 ], 37 | [ 1010, 519, 145, 108 ] 38 | ], 39 | "action": "Click", 40 | "post_delay": 1500 41 | }, 42 | "Sub_Start_TacticalChallenge_Partial": { 43 | "doc": "times_limit setted in code", 44 | "is_sub": true, 45 | "times_limit": 5, 46 | "recognition": "OCR", 47 | "text": "TacticalChallenge", 48 | "roi": [ 0, 0, 450, 60 ], 49 | "next": [ 50 | "End_TacticalChallenge", 51 | "Click_RankByTheFront_Partial" 52 | ], 53 | "runout_next": [ 54 | "Sub_End_TacticalChallenge_Partial" 55 | ] 56 | }, 57 | "End_TacticalChallenge": { 58 | "skip_review": 4, 59 | "model": "../../../Base/model/ocr/", 60 | "recognition": "OCR", 61 | "text": [ "0/5", "^0.?5$", "[oO0oO0][11//55]" ], 62 | "roi": [ 147, 447, 148, 101 ], 63 | "next": [ 64 | "Sub_End_TacticalChallenge_Partial" 65 | ] 66 | }, 67 | "Sub_End_TacticalChallenge_Partial": { 68 | "doc": "times_limit: 0 setted in code, 0 -> TacticalChallenge0", 69 | "is_sub": true, 70 | "times_limit": 1, 71 | "recognition": "OCR", 72 | "text": "TacticalChallenge", 73 | "roi": [ 0, 0, 450, 150 ], 74 | "next": [ 75 | "Click_ClaimButton_ForPyroxenes_Partial" 76 | ], 77 | "runout_next": [ 78 | "TacticalChallenge0" 79 | ] 80 | }, 81 | "Click_ClaimButton_ForCreditPoints_Partial": { 82 | "TODO": "颜色匹配", 83 | "target": [ 307, 359, 89, 58 ], 84 | "action": "Click", 85 | "post_delay": 1000, 86 | "next": [ 87 | "Click_TouchButton_Partial" 88 | ], 89 | "timeout": 5000 90 | }, 91 | "Click_ClaimButton_ForPyroxenes_Partial": { 92 | "TODO": "颜色匹配", 93 | "target": [ 307, 438, 89, 58 ], 94 | "action": "Click", 95 | "next": [ 96 | "Click_TouchButton_Partial" 97 | ], 98 | "timeout": 5000 99 | }, 100 | "Click_RankByTheFront_Partial": { 101 | "recognition": "OCR", 102 | "text": "Rank", 103 | "roi": [ 458, 174, 778, 150 ], 104 | "target": [ 458, 174, 778, 150 ], 105 | "action": "Click", 106 | "next": [ 107 | "ZeroTicket1Flag", 108 | "Click_FormationButton_Partial" 109 | ] 110 | }, 111 | "ZeroTicket1Flag": { 112 | "skip_review": 6, 113 | "recognition": "TemplateMatch", 114 | "template": "../../Base/image/TacticalChallenge/ZeroTicket1.png", 115 | "roi": [ 646, 460, 154, 129 ], 116 | "next": [ 117 | "Sub_Click_CloseButton", 118 | "Stop" 119 | ] 120 | }, 121 | "Click_FormationButton_Partial": { 122 | "recognition": "OCR", 123 | "text": "Formation", 124 | "roi": [ 537, 537, 205, 70 ], 125 | "target": [ 537, 537, 205, 70 ], 126 | "action": "Click", 127 | "post_delay": 1500, 128 | "next": [ 129 | "Notice_TimedOut_Partial", 130 | "Notice_InsufficientTacticalChallengeTickets", 131 | "Sub_Wait_NowLoading_Partial", 132 | "Sub_Click_SkipTactics_Partial", 133 | "Click_MobilizeButton_Partial" 134 | ] 135 | }, 136 | "Notice_InsufficientTacticalChallengeTickets": { 137 | "skip_review": 6, 138 | "recognition": "TemplateMatch", 139 | "template": "../../Base/image/TacticalChallenge/Pyroxene.png", 140 | "roi": [ 565, 345, 135, 138 ], 141 | "next": [ 142 | "Sub_Click_CloseButton", 143 | "Stop" 144 | ] 145 | }, 146 | "Sub_Click_SkipTactics_Partial": { 147 | "is_sub": true, 148 | "recognition": "TemplateMatch", 149 | "template": "Arona.png", 150 | "threshold": 0.9, 151 | "roi": [ 1040, 532, 240, 143 ], 152 | "target": [ 1090, 582, 160, 43 ], 153 | "action": "Click" 154 | }, 155 | "Click_MobilizeButton_Partial": { 156 | "recognition": "OCR", 157 | "text": "Mobilize", 158 | "roi": [ 1089, 636, 156, 68 ], 159 | "target": [ 1089, 636, 156, 68 ], 160 | "action": "Click", 161 | "post_delay": 1500, 162 | "next": [ 163 | "Sub_Wait_NowLoading_Partial", 164 | "Notice_TimedOut_Partial", 165 | "Notice_RankChanged_Partial", 166 | "Notice_Standby_Partial", 167 | "Sub_Click_PassButton", 168 | "Click_ConfirmButton_OnBattleComplete_Partial", 169 | "Click_MobilizeButton_Partial", 170 | "Notice_BattleResult_Partial" 171 | ] 172 | }, 173 | "Click_ConfirmButton_OnBattleComplete_Partial": { 174 | "recognition": "OCR", 175 | "text": "Confirm", 176 | "roi": [ 177 | [ 1109, 634, 122, 60 ], 178 | [ 533, 624, 215, 72 ] 179 | ], 180 | "action": "Click", 181 | "next": [ 182 | "Click_ConfirmButton_OnRewardAcquired_Partial" 183 | ] 184 | }, 185 | "Click_ConfirmButton_OnRewardAcquired_Partial": { 186 | "recognition": "OCR", 187 | "text": "Confirm", 188 | "roi": [ 540, 625, 201, 69 ], 189 | "target": [ 540, 625, 201, 69 ], 190 | "action": "Click", 191 | "next": [ 192 | "TacticalChallengeFlag_Partial" 193 | ] 194 | }, 195 | "TacticalChallengeFlag_Partial": { 196 | "recognition": "OCR", 197 | "text": "TacticalChallenge", 198 | "roi": [ 0, 0, 450, 60 ] 199 | }, 200 | "Notice_TimedOut_Partial": { 201 | "recognition": "OCR", 202 | "text": "List refresh timed out.", 203 | "roi": [ 360, 135, 560, 440 ], 204 | "target": [ 537, 467, 204, 69 ], 205 | "action": "Click", 206 | "next": [ 207 | "Sub_Wait_NowLoading_Partial", 208 | "Click_RankByTheFront_Partial" 209 | ] 210 | }, 211 | "Notice_RankChanged_Partial": { 212 | "recognition": "OCR", 213 | "text": "RankChanged", 214 | "roi": [ 360, 135, 560, 440 ], 215 | "target": [ 537, 467, 204, 69 ], 216 | "action": "Click", 217 | "next": [ 218 | "Sub_Wait_NowLoading_Partial", 219 | "Click_RankByTheFront_Partial" 220 | ] 221 | }, 222 | "Notice_Standby_Partial": { 223 | "recognition": "OCR", 224 | "text": "Standby", 225 | "roi": [ 360, 135, 560, 440 ], 226 | "target": [ 531, 431, 217, 71 ], 227 | "action": "Click", 228 | "pre_delay": 50000, 229 | "next": [ 230 | "Click_MobilizeButton_Partial" 231 | ] 232 | }, 233 | "Notice_BattleResult_Partial": { 234 | "recognition": "OCR", 235 | "text": "BattleResult", 236 | "roi": [ 360, 135, 560, 440 ], 237 | "notify": true, 238 | "next": [ 239 | "Notice_Click_ConfirmButton_Partial" 240 | ] 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "Tasks": { 3 | "next": [ 4 | "Sub_Wait_NowLoading_Partial", 5 | "Sub_Goto_Tasks_Partial", 6 | "Sub_Click_ClaimAllButton_Tasks_Partial", 7 | "Sub_Click_ClaimButton_Tasks_Partial", 8 | "Stop" 9 | ] 10 | }, 11 | "Sub_Goto_Tasks_Partial": { 12 | "is_sub": true, 13 | "inverse": true, 14 | "recognition": "OCR", 15 | "text": "Tasks", 16 | "roi": [ 0, 0, 450, 60 ], 17 | "next": [ 18 | "Click_TasksButton", 19 | "Sub_Wait_NowLoading_Partial", 20 | "Sub_Goto_Home" 21 | ] 22 | }, 23 | "Click_TasksButton": { 24 | "skip_review": 6, 25 | "recognition": "TemplateMatch", 26 | "template": "../../Base/image/Tasks/Tasks.png", 27 | "roi": [ 2, 171, 127, 126 ], 28 | "action": "Click", 29 | "post_delay": 1500 30 | }, 31 | "Sub_Click_ClaimAllButton_Tasks_Partial": { 32 | "TODO": "使用颜色匹配", 33 | "is_sub": true, 34 | "recognition": "TemplateMatch", 35 | "template": "Arona.png", 36 | "threshold": 0.9, 37 | "roi": [ 1003, 589, 277, 131 ], 38 | "action": "Click", 39 | "next": [ 40 | "Click_TouchButton_Partial" 41 | ] 42 | }, 43 | "Sub_Click_ClaimButton_Tasks_Partial": { 44 | "TODO": "使用颜色匹配", 45 | "is_sub": true, 46 | "recognition": "TemplateMatch", 47 | "template": "Arona.png", 48 | "threshold": 0.9, 49 | "roi": [ 880, 591, 185, 129 ], 50 | "action": "Click", 51 | "next": [ 52 | "Click_TouchButton_Partial" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Test.json: -------------------------------------------------------------------------------- 1 | { 2 | "Test": { 3 | "next": [ 4 | "Test1", 5 | "Stop" 6 | ] 7 | }, 8 | "Test1": { 9 | "recognition": "Custom", 10 | "custom_recognizer": "ColorMatch", 11 | "custom_recognizer_param": { 12 | "a": "a" 13 | }, 14 | "roi": [ 1143, 543, 35, 50 ], 15 | "action": "Click" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /assets/Resource/Base/pipeline/Utils.json: -------------------------------------------------------------------------------- 1 | { 2 | "Stop": {}, 3 | "None": { 4 | "doc": "和 Stop 行为相同,但只会在 Enum.ToString() 时用到" 5 | }, 6 | "StopOnException": { 7 | "TODO": "StopTaskOnException 属于不正常退出,等 focus 完善。" 8 | }, 9 | "StopTask": { 10 | "action": "StopTask" 11 | }, 12 | "StopTaskOnException": { 13 | "TODO": "StopTaskOnException 属于不正常退出,等 focus 完善。", 14 | "action": "StopTask" 15 | }, 16 | "TODO": { 17 | "action": "StopTask" 18 | }, 19 | "Back": { 20 | "action": "Key", 21 | "key": 4 22 | }, 23 | "Sub_Back": { 24 | "is_sub": true, 25 | "action": "Key", 26 | "key": 4 27 | }, 28 | "Sub_Wait_NowLoading_Partial": { 29 | "is_sub": true, 30 | "recognition": "OCR", 31 | "text": "NowLoading", 32 | "roi": [ 922, 642, 204, 43 ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /assets/Resource/Base/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "is_base": true, 3 | "version": "Base.0" 4 | } 5 | -------------------------------------------------------------------------------- /assets/Resource/EN/image/Campaign/TacticalChallenge/SkipTactics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/EN/image/Campaign/TacticalChallenge/SkipTactics.png -------------------------------------------------------------------------------- /assets/Resource/EN/image/Crafting/MaterialFusion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/EN/image/Crafting/MaterialFusion.png -------------------------------------------------------------------------------- /assets/Resource/EN/image/Crafting/MaterialSynthesis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/EN/image/Crafting/MaterialSynthesis.png -------------------------------------------------------------------------------- /assets/Resource/EN/image/Tasks/Claim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/EN/image/Tasks/Claim.png -------------------------------------------------------------------------------- /assets/Resource/EN/image/Tasks/ClaimAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/EN/image/Tasks/ClaimAll.png -------------------------------------------------------------------------------- /assets/Resource/EN/pipeline/TemplateMatchPartialTasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sub_Click_SkipTactics_Partial": { 3 | "template": "../image/Campaign/TacticalChallenge/SkipTactics.png" 4 | }, 5 | "Sub_Goto_MaterialSynthesis_Partial": { 6 | "template": "../image/Crafting/MaterialFusion.png" 7 | }, 8 | "Sub_Goto_MaterialFusion_Partial": { 9 | "template": "../image/Crafting/MaterialSynthesis.png" 10 | }, 11 | "Click_MaterialSynthesis_Partial": { 12 | "template": "../image/Crafting/MaterialSynthesis.png" 13 | }, 14 | "Click_MaterialFusion_Partial": { 15 | "template": "../image/Crafting/MaterialFusion.png" 16 | }, 17 | "Sub_Click_ClaimAllButton_Tasks_Partial": { 18 | "template": "../image/Tasks/ClaimAll.png" 19 | }, 20 | "Sub_Click_ClaimButton_Tasks_Partial": { 21 | "template": "../image/Tasks/Claim.png" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /assets/Resource/EN/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "is_base": false, 3 | "version": "EN.0" 4 | } 5 | -------------------------------------------------------------------------------- /assets/Resource/SC/image/Campaign/TacticalChallenge/SkipTactics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/SC/image/Campaign/TacticalChallenge/SkipTactics.png -------------------------------------------------------------------------------- /assets/Resource/SC/image/Crafting/MaterialFusion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/SC/image/Crafting/MaterialFusion.png -------------------------------------------------------------------------------- /assets/Resource/SC/image/Crafting/MaterialSynthesis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/SC/image/Crafting/MaterialSynthesis.png -------------------------------------------------------------------------------- /assets/Resource/SC/image/Tasks/Claim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/SC/image/Tasks/Claim.png -------------------------------------------------------------------------------- /assets/Resource/SC/image/Tasks/ClaimAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/SC/image/Tasks/ClaimAll.png -------------------------------------------------------------------------------- /assets/Resource/SC/model/ocr/README.md: -------------------------------------------------------------------------------- 1 | # PaddleOCR model 2 | 3 | 2023/07/06 4 | 5 | from 6 | 7 | ## det model 8 | 9 | ch_PP-OCRv3_det 10 | [New] Original lightweight model, supporting Chinese, English, multilingual text detection 11 | 12 | 13 | 14 | ## rec model 15 | 16 | ch_PP-OCRv3_rec 17 | [New] Original lightweight model, supporting Chinese, English, multilingual text recognition 18 | 19 | 20 | 21 | ## rec label 22 | 23 | 24 | -------------------------------------------------------------------------------- /assets/Resource/SC/model/ocr/det.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/SC/model/ocr/det.onnx -------------------------------------------------------------------------------- /assets/Resource/SC/model/ocr/rec.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/SC/model/ocr/rec.onnx -------------------------------------------------------------------------------- /assets/Resource/SC/pipeline/Bounty.json: -------------------------------------------------------------------------------- 1 | { 2 | "BountyChinese": { 3 | "next": [ 4 | "Sub_Wait_NowLoading_Partial", 5 | "Sub_Goto_Bounty_Partial", 6 | "Sub_Check_OverpassTicket", 7 | "Sub_Check_DesertRailroadTicket", 8 | "Sub_Check_ClassroomTicket", 9 | "Stop" 10 | ] 11 | }, 12 | "Check_BountyTicket": { 13 | "enabled": false 14 | }, 15 | "Sub_Goto_Bounty_Partial": { 16 | "roi": [ 630, 125, 650, 70 ] 17 | }, 18 | "Sub_Check_OverpassTicket": { 19 | "skip_review": 4, 20 | "model": "../../../Base/model/ocr/", 21 | "is_sub": true, 22 | "inverse": true, 23 | "times_limit": 5, 24 | "recognition": "OCR", 25 | "text": [ "0/2", "0/" ], 26 | "roi": [ 680, 210, 600, 136 ], 27 | "next": [ 28 | "Sub_Wait_NowLoading_Partial", 29 | "Sub_Goto_Overpass_Partial", 30 | "Start_SweepMission_OnBounty" 31 | ], 32 | "runout_next": [ 33 | "Sub_Wait_NowLoading_Partial", 34 | "Sub_Goto_Bounty_Partial", 35 | "Sub_Check_DesertRailroadTicket", 36 | "Sub_Check_ClassroomTicket", 37 | "StopTask" 38 | ] 39 | }, 40 | "Sub_Check_DesertRailroadTicket": { 41 | "skip_review": 4, 42 | "model": "../../../Base/model/ocr/", 43 | "is_sub": true, 44 | "inverse": true, 45 | "times_limit": 5, 46 | "recognition": "OCR", 47 | "text": [ "0/2", "0/" ], 48 | "roi": [ 680, 346, 600, 136 ], 49 | "next": [ 50 | "Sub_Wait_NowLoading_Partial", 51 | "Sub_Goto_DesertRailroad_Partial", 52 | "Start_SweepMission_OnBounty" 53 | ], 54 | "runout_next": [ 55 | "Sub_Wait_NowLoading_Partial", 56 | "Sub_Goto_Bounty_Partial", 57 | "Sub_Check_ClassroomTicket", 58 | "StopTask" 59 | ] 60 | }, 61 | "Sub_Check_ClassroomTicket": { 62 | "skip_review": 4, 63 | "model": "../../../Base/model/ocr/", 64 | "is_sub": true, 65 | "inverse": true, 66 | "times_limit": 5, 67 | "recognition": "OCR", 68 | "text": [ "0/2", "0/" ], 69 | "roi": [ 680, 482, 600, 136 ], 70 | "next": [ 71 | "Sub_Wait_NowLoading_Partial", 72 | "Sub_Goto_Classroom_Partial", 73 | "Start_SweepMission_OnBounty" 74 | ], 75 | "runout_next": [ 76 | "StopTask" 77 | ] 78 | }, 79 | "Click_Overpass_Partial": { 80 | "roi": [ 680, 210, 600, 136 ] 81 | }, 82 | "Click_DesertRailroad_Partial": { 83 | "roi": [ 680, 346, 600, 136 ] 84 | }, 85 | "Click_Classroom_Partial": { 86 | "roi": [ 680, 482, 600, 136 ] 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /assets/Resource/SC/pipeline/Commissions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sub_Goto_Commissions_Partial": { 3 | "roi": [ 630, 125, 650, 83 ] 4 | }, 5 | "Click_BaseDefense_Partial": { 6 | "roi": [ 685, 210, 560, 120 ] 7 | }, 8 | "Click_ItemRetrieval_Partial": { 9 | "roi": [ 685, 330, 560, 120 ] 10 | }, 11 | "Start_SweepMission_OnCommissions": { 12 | "next": [ 13 | "Start_SweepMission_Partial", 14 | "Sub_Click_EnterButton_OnClearedMission_Partial", 15 | "StopOnException" 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /assets/Resource/SC/pipeline/DisabledTasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "Start_SweepMission_Partial": { 3 | "doc": "Click_MaxButton disabled,保持不同服之间 diff_task 相同", 4 | "next": [ 5 | "Click_PlusButton" 6 | ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /assets/Resource/SC/pipeline/OCRPartialTasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "MenuFlag_Partial": { 3 | "text": [ 4 | "菜单" 5 | ] 6 | }, 7 | "CampaignFlag_Partial": { 8 | "text": [ 9 | "业务区", 10 | "业务" 11 | ] 12 | }, 13 | "Sub_Wait_NowLoading_Partial": { 14 | "model": "../../../Base/model/ocr/", 15 | "text": [ 16 | "Loading" 17 | ] 18 | }, 19 | "Sub_Notice_Partial": { 20 | "text": [ 21 | "通知" 22 | ] 23 | }, 24 | "Notice_Click_CancelButton_Partial": { 25 | "text": [ 26 | "取消" 27 | ] 28 | }, 29 | "Notice_Click_ConfirmButton_Partial": { 30 | "text": [ 31 | "确认" 32 | ] 33 | }, 34 | "Click_ConfirmButton_OnBattleComplete_Partial": { 35 | "text": [ 36 | "确认" 37 | ] 38 | }, 39 | "Click_ConfirmButton_OnRewardAcquired_Partial": { 40 | "text": [ 41 | "确认" 42 | ] 43 | }, 44 | "Notice_Click_ConfirmButton_OnInviting_Partial": { 45 | "text": [ 46 | "确认" 47 | ] 48 | }, 49 | "Notice_Click_ConfirmButton_OnSweeping_Partial": { 50 | "text": [ 51 | "确认" 52 | ] 53 | }, 54 | "Click_ConfirmButton_OnSweeped_Partial": { 55 | "text": [ 56 | "确认" 57 | ] 58 | }, 59 | "Sub_Notice_Quit_Partial": { 60 | "text": [ 61 | "是否结束游戏" 62 | ] 63 | }, 64 | "Notice_TimedOut_Partial": { 65 | "text": [ 66 | "已超出编队时间限制", 67 | "超出..时间" 68 | ] 69 | }, 70 | "Notice_RankChanged_Partial": { 71 | "text": [ 72 | "The opponent's rank has changed.", 73 | "rank has changed", 74 | "has changed" 75 | ] 76 | }, 77 | "Notice_Standby_Partial": { 78 | "text": [ 79 | "等待时间" 80 | ] 81 | }, 82 | "Notice_BattleResult_Partial": { 83 | "text": [ 84 | "对战结果" 85 | ] 86 | }, 87 | "Sub_Goto_Mailbox_Partial": { 88 | "text": [ 89 | "邮箱" 90 | ] 91 | }, 92 | "NoMoreMailFlag_Partial": { 93 | "text": [ 94 | "暂无邮件" 95 | ] 96 | }, 97 | "Click_ClaimAllButton_Mailbox_Partial": { 98 | "text": [ 99 | "一键领取" 100 | ] 101 | }, 102 | "Sub_Goto_Club_Partial": { 103 | "text": [ 104 | "小组大厅" 105 | ] 106 | }, 107 | "Click_ClubButton_Partial": { 108 | "text": [ 109 | "小组" 110 | ] 111 | }, 112 | "TacticalChallengeFlag_Partial": { 113 | "text": [ 114 | "战术对抗赛", 115 | "战术" 116 | ] 117 | }, 118 | "Sub_Goto_TacticalChallenge_Partial": { 119 | "text": [ 120 | "战术对抗赛", 121 | "战术" 122 | ] 123 | }, 124 | "Sub_Start_TacticalChallenge_Partial": { 125 | "text": [ 126 | "战术对抗赛", 127 | "战术" 128 | ] 129 | }, 130 | "Sub_End_TacticalChallenge_Partial": { 131 | "text": [ 132 | "战术对抗赛", 133 | "战术" 134 | ] 135 | }, 136 | "Click_TacticalChallenge_Partial": { 137 | "text": [ 138 | "战术对抗赛", 139 | "战术" 140 | ] 141 | }, 142 | "Click_ClaimButton_ForCreditPoints_Partial": { 143 | "text": [ 144 | "领取" 145 | ] 146 | }, 147 | "Click_ClaimButton_ForPyroxenes_Partial": { 148 | "text": [ 149 | "领取" 150 | ] 151 | }, 152 | "Click_TouchButton_Partial": { 153 | "text": [ 154 | "点击继续", 155 | "点击", 156 | "继续" 157 | ] 158 | }, 159 | "Start_SweepMission_Partial": { 160 | "text": [ 161 | "任务信息" 162 | ] 163 | }, 164 | "Click_StartSweepButton_Partial": { 165 | "text": [ 166 | "开始快速战斗" 167 | ] 168 | }, 169 | "Click_SkipButton_Partial": { 170 | "text": [ 171 | "跳过" 172 | ] 173 | }, 174 | "Sub_Click_EnterButton_OnClearedMission_Partial": { 175 | "text": [ 176 | "入场" 177 | ] 178 | }, 179 | "Click_RankByTheFront_Partial": { 180 | "text": [ 181 | "第" 182 | ] 183 | }, 184 | "Click_FormationButton_Partial": { 185 | "text": [ 186 | "编队" 187 | ] 188 | }, 189 | "Click_MobilizeButton_Partial": { 190 | "text": [ 191 | "出击" 192 | ] 193 | }, 194 | "Sub_Goto_Cafe_Partial": { 195 | "text": [ 196 | "沙勒附属", 197 | "咖啡厅" 198 | ] 199 | }, 200 | "Click_CafeButton_Partial": { 201 | "text": [ 202 | "咖啡厅" 203 | ] 204 | }, 205 | "Sub_Check_RelationshipRankUp_Partial": { 206 | "text": [ 207 | "距离", 208 | "下一次访问" 209 | ] 210 | }, 211 | "Sub_Click_InvitationButton_Partial": { 212 | "text": [ 213 | "可以使用" 214 | ] 215 | }, 216 | "Click_InvitationButton_Partial": { 217 | "text": [ 218 | "可以使用" 219 | ] 220 | }, 221 | "Click_InviteButton_Partial": { 222 | "text": [ 223 | "邀请" 224 | ] 225 | }, 226 | "Sub_Click_CafeEarningsButton_Partial": { 227 | "text": [ 228 | "可获得", 229 | "已满", 230 | "可获." 231 | ] 232 | }, 233 | "Click_CafeEarningsButton_Partial": { 234 | "text": [ 235 | "可获得", 236 | "已满", 237 | "可获." 238 | ] 239 | }, 240 | "Click_ClaimButton_ForCafeEarnings_Partial": { 241 | "text": [ 242 | "领取" 243 | ] 244 | }, 245 | "Click_ComfortButton_Partial": { 246 | "text": [ 247 | "舒适度" 248 | ] 249 | }, 250 | "Click_RankUpButton_OnCafeInfo_Partial": { 251 | "text": [ 252 | "提升评级" 253 | ] 254 | }, 255 | "Click_RankUpButton_OnCafeRankUp_Partial": { 256 | "text": [ 257 | "提升评级" 258 | ] 259 | }, 260 | "Sub_Goto_Scrimmage_Partial": { 261 | "skip_review": 4 262 | }, 263 | "Click_ScrimmageButton_Partial": { 264 | "skip_review": 4 265 | }, 266 | "ScrimmageFlag_Partial": { 267 | "skip_review": 4 268 | }, 269 | "Sub_Goto_Trinity_Partial": { 270 | "skip_review": 4 271 | }, 272 | "Click_Trinity_Partial": { 273 | "skip_review": 4 274 | }, 275 | "Sub_Goto_Gehenna_Partial": { 276 | "skip_review": 4 277 | }, 278 | "Click_Gehenna_Partial": { 279 | "skip_review": 4 280 | }, 281 | "Sub_Goto_Millennium_Partial": { 282 | "skip_review": 4 283 | }, 284 | "Click_Millennium_Partial": { 285 | "skip_review": 4 286 | }, 287 | "Click_CommissionsButton_Partial": { 288 | "text": [ 289 | "特别委托" 290 | ] 291 | }, 292 | "CommissionsFlag_Partial": { 293 | "text": [ 294 | "特别委托" 295 | ] 296 | }, 297 | "Sub_Goto_Commissions_Partial": { 298 | "model": "../../../Base/model/ocr/", 299 | "text": [ 300 | "Request Select", 301 | "RequestSelect", 302 | "R.*Select" 303 | ] 304 | }, 305 | "Sub_Goto_BaseDefense_Partial": { 306 | "text": [ 307 | "据点防御", 308 | "据点" 309 | ] 310 | }, 311 | "Click_BaseDefense_Partial": { 312 | "text": [ 313 | "据点防御", 314 | "据点" 315 | ] 316 | }, 317 | "Sub_Goto_ItemRetrieval_Partial": { 318 | "text": [ 319 | "信用回收", 320 | "信用" 321 | ] 322 | }, 323 | "Click_ItemRetrieval_Partial": { 324 | "text": [ 325 | "信用回收", 326 | "信用" 327 | ] 328 | }, 329 | "Sub_Goto_Bounty_Partial": { 330 | "model": "../../../Base/model/ocr/", 331 | "text": [ 332 | "Location Select", 333 | "LocationSelect", 334 | "L.*Select" 335 | ] 336 | }, 337 | "Click_BountyButton_Partial": { 338 | "text": [ 339 | "悬赏通缉", 340 | "悬赏", 341 | "通缉" 342 | ] 343 | }, 344 | "BountyFlag_Partial": { 345 | "text": [ 346 | "悬赏通缉", 347 | "悬赏", 348 | "通缉" 349 | ] 350 | }, 351 | "Sub_Goto_Overpass_Partial": { 352 | "text": [ 353 | "高架公路" 354 | ] 355 | }, 356 | "Click_Overpass_Partial": { 357 | "text": [ 358 | "高架公路" 359 | ] 360 | }, 361 | "Sub_Goto_DesertRailroad_Partial": { 362 | "text": [ 363 | "沙漠铁路" 364 | ] 365 | }, 366 | "Click_DesertRailroad_Partial": { 367 | "text": [ 368 | "沙漠铁路" 369 | ] 370 | }, 371 | "Sub_Goto_Classroom_Partial": { 372 | "text": [ 373 | "讲堂" 374 | ] 375 | }, 376 | "Click_Classroom_Partial": { 377 | "text": [ 378 | "讲堂" 379 | ] 380 | }, 381 | "Sub_Goto_Tasks_Partial": { 382 | "text": [ 383 | "工作任务" 384 | ] 385 | }, 386 | "Sub_Click_SignIn_Partial": { 387 | "text": [ 388 | "^第.*天$" 389 | ] 390 | }, 391 | "0": { 392 | "text": [ 393 | "00" 394 | ] 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /assets/Resource/SC/pipeline/Scrimmage.json: -------------------------------------------------------------------------------- 1 | { 2 | "ScrimmageChinese": { 3 | "next": [ 4 | "Sub_Wait_NowLoading_Partial", 5 | "Sub_Goto_Scrimmage_Partial", 6 | "Sub_Check_TrinityTicket", 7 | "Sub_Check_GehennaTicket", 8 | "Sub_Check_MillenniumTicket", 9 | "Stop" 10 | ] 11 | }, 12 | "Check_ScrimmageTicket": { 13 | "enabled": false 14 | }, 15 | "Sub_Goto_Scrimmage_Partial": { 16 | "skip_review": 4, 17 | "roi": [ 630, 125, 650, 70 ] 18 | }, 19 | "Sub_Check_TrinityTicket": { 20 | "skip_review": 4, 21 | "model": "../../../Base/model/ocr/", 22 | "is_sub": true, 23 | "inverse": true, 24 | "times_limit": 5, 25 | "recognition": "OCR", 26 | "text": [ "0/2", "0/" ], 27 | "roi": [ 680, 210, 600, 136 ], 28 | "next": [ 29 | "Sub_Wait_NowLoading_Partial", 30 | "Sub_Goto_Trinity_Partial", 31 | "Start_SweepMission_OnScrimmage" 32 | ], 33 | "runout_next": [ 34 | "Sub_Wait_NowLoading_Partial", 35 | "Sub_Goto_Scrimmage_Partial", 36 | "Sub_Check_GehennaTicket", 37 | "Sub_Check_MillenniumTicket", 38 | "StopTask" 39 | ] 40 | }, 41 | "Sub_Check_GehennaTicket": { 42 | "skip_review": 4, 43 | "model": "../../../Base/model/ocr/", 44 | "is_sub": true, 45 | "inverse": true, 46 | "times_limit": 5, 47 | "recognition": "OCR", 48 | "text": [ "0/2", "0/" ], 49 | "roi": [ 680, 346, 600, 136 ], 50 | "next": [ 51 | "Sub_Wait_NowLoading_Partial", 52 | "Sub_Goto_Gehenna_Partial", 53 | "Start_SweepMission_OnScrimmage" 54 | ], 55 | "runout_next": [ 56 | "Sub_Wait_NowLoading_Partial", 57 | "Sub_Goto_Scrimmage_Partial", 58 | "Sub_Check_MillenniumTicket", 59 | "StopTask" 60 | ] 61 | }, 62 | "Sub_Check_MillenniumTicket": { 63 | "skip_review": 4, 64 | "model": "../../../Base/model/ocr/", 65 | "is_sub": true, 66 | "inverse": true, 67 | "times_limit": 5, 68 | "recognition": "OCR", 69 | "text": [ "0/2", "0/" ], 70 | "roi": [ 680, 482, 600, 136 ], 71 | "next": [ 72 | "Sub_Wait_NowLoading_Partial", 73 | "Sub_Goto_Millennium_Partial", 74 | "Start_SweepMission_OnScrimmage" 75 | ], 76 | "runout_next": [ 77 | "StopTask" 78 | ] 79 | }, 80 | "Click_Trinity_Partial": { 81 | "skip_review": 4, 82 | "roi": [ 680, 210, 600, 136 ] 83 | }, 84 | "Click_Gehenna_Partial": { 85 | "skip_review": 4, 86 | "roi": [ 680, 346, 600, 136 ] 87 | }, 88 | "Click_Millennium_Partial": { 89 | "skip_review": 4, 90 | "roi": [ 680, 482, 600, 136 ] 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /assets/Resource/SC/pipeline/TemplateMatchPartialTasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sub_Click_SkipTactics_Partial": { 3 | "template": "../image/Campaign/TacticalChallenge/SkipTactics.png" 4 | }, 5 | "Sub_Goto_MaterialSynthesis_Partial": { 6 | "template": "../image/Crafting/MaterialFusion.png" 7 | }, 8 | "Sub_Goto_MaterialFusion_Partial": { 9 | "template": "../image/Crafting/MaterialSynthesis.png" 10 | }, 11 | "Click_MaterialSynthesis_Partial": { 12 | "template": "../image/Crafting/MaterialSynthesis.png" 13 | }, 14 | "Click_MaterialFusion_Partial": { 15 | "template": "../image/Crafting/MaterialFusion.png" 16 | }, 17 | "Sub_Click_ClaimAllButton_Tasks_Partial": { 18 | "template": "../image/Tasks/ClaimAll.png" 19 | }, 20 | "Sub_Click_ClaimButton_Tasks_Partial": { 21 | "template": "../image/Tasks/Claim.png" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /assets/Resource/SC/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "is_base": false, 3 | "version": "SC.0" 4 | } 5 | -------------------------------------------------------------------------------- /assets/Resource/TC/image/Campaign/TacticalChallenge/SkipTactics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/TC/image/Campaign/TacticalChallenge/SkipTactics.png -------------------------------------------------------------------------------- /assets/Resource/TC/image/Crafting/MaterialFusion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/TC/image/Crafting/MaterialFusion.png -------------------------------------------------------------------------------- /assets/Resource/TC/image/Crafting/MaterialSynthesis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/TC/image/Crafting/MaterialSynthesis.png -------------------------------------------------------------------------------- /assets/Resource/TC/image/Tasks/Claim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/TC/image/Tasks/Claim.png -------------------------------------------------------------------------------- /assets/Resource/TC/image/Tasks/ClaimAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/TC/image/Tasks/ClaimAll.png -------------------------------------------------------------------------------- /assets/Resource/TC/model/ocr/README.md: -------------------------------------------------------------------------------- 1 | # PaddleOCR model 2 | 3 | 2023/07/06 4 | 5 | from 6 | 7 | ## det model 8 | 9 | ch_PP-OCRv3_det 10 | [New] Original lightweight model, supporting Chinese, English, multilingual text detection 11 | 12 | 13 | 14 | ## rec model 15 | 16 | chinese_cht_PP-OCRv3_rec 17 | Lightweight model for chinese cht 18 | 19 | 20 | 21 | ## rec label 22 | 23 | 24 | -------------------------------------------------------------------------------- /assets/Resource/TC/model/ocr/det.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/TC/model/ocr/det.onnx -------------------------------------------------------------------------------- /assets/Resource/TC/model/ocr/rec.onnx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/Resource/TC/model/ocr/rec.onnx -------------------------------------------------------------------------------- /assets/Resource/TC/pipeline/TemplateMatchPartialTasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "Sub_Click_SkipTactics_Partial": { 3 | "template": "../image/Campaign/TacticalChallenge/SkipTactics.png" 4 | }, 5 | "Sub_Goto_MaterialSynthesis_Partial": { 6 | "template": "../image/Crafting/MaterialFusion.png" 7 | }, 8 | "Sub_Goto_MaterialFusion_Partial": { 9 | "template": "../image/Crafting/MaterialSynthesis.png" 10 | }, 11 | "Click_MaterialSynthesis_Partial": { 12 | "template": "../image/Crafting/MaterialSynthesis.png" 13 | }, 14 | "Click_MaterialFusion_Partial": { 15 | "template": "../image/Crafting/MaterialFusion.png" 16 | }, 17 | "Sub_Click_ClaimAllButton_Tasks_Partial": { 18 | "template": "../image/Tasks/ClaimAll.png" 19 | }, 20 | "Sub_Click_ClaimButton_Tasks_Partial": { 21 | "template": "../image/Tasks/Claim.png" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /assets/Resource/TC/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "is_base": false, 3 | "version": "TC.0" 4 | } 5 | -------------------------------------------------------------------------------- /assets/Resource/controller_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "prebuilt": { 3 | "minicap": { 4 | "root": "./MaaAgentBinary/minicap", 5 | "arch": [ 6 | "x86", 7 | "armeabi-v7a", 8 | "armeabi" 9 | ], 10 | "sdk": [ 11 | 31, 12 | 29, 13 | 28, 14 | 27, 15 | 26, 16 | 25, 17 | 24, 18 | 23, 19 | 22, 20 | 21, 21 | 19, 22 | 18, 23 | 17, 24 | 16, 25 | 15, 26 | 14 27 | ] 28 | }, 29 | "minitouch": { 30 | "root": "./MaaAgentBinary/minitouch", 31 | "arch": [ 32 | "x86_64", 33 | "x86", 34 | "arm64-v8a", 35 | "armeabi-v7a", 36 | "armeabi" 37 | ] 38 | }, 39 | "maatouch": { 40 | "root": "./MaaAgentBinary/maatouch", 41 | "package": "com.shxyke.MaaTouch.App" 42 | } 43 | }, 44 | "command": { 45 | "Connect": [ 46 | "{ADB}", 47 | "connect", 48 | "{ADB_SERIAL}" 49 | ], 50 | "KillServer": [ 51 | "{ADB}", 52 | "kill-server" 53 | ], 54 | "UUID": [ 55 | "{ADB}", 56 | "-s", 57 | "{ADB_SERIAL}", 58 | "shell", 59 | "settings get secure android_id" 60 | ], 61 | "Resolution": [ 62 | "{ADB}", 63 | "-s", 64 | "{ADB_SERIAL}", 65 | "shell", 66 | "dumpsys window displays | grep -o -E cur=+[^\\ ]+ | grep -o -E [0-9]+" 67 | ], 68 | "StartApp": [ 69 | "{ADB}", 70 | "-s", 71 | "{ADB_SERIAL}", 72 | "shell", 73 | "am start -n {INTENT}" 74 | ], 75 | "StopApp": [ 76 | "{ADB}", 77 | "-s", 78 | "{ADB_SERIAL}", 79 | "shell", 80 | "am force-stop {INTENT}" 81 | ], 82 | "Click": [ 83 | "{ADB}", 84 | "-s", 85 | "{ADB_SERIAL}", 86 | "shell", 87 | "input tap {X} {Y}" 88 | ], 89 | "Swipe": [ 90 | "{ADB}", 91 | "-s", 92 | "{ADB_SERIAL}", 93 | "shell", 94 | "input swipe {X1} {Y1} {X2} {Y2} {DURATION}" 95 | ], 96 | "PressKey": [ 97 | "{ADB}", 98 | "-s", 99 | "{ADB_SERIAL}", 100 | "shell", 101 | "input keyevent {KEY}" 102 | ], 103 | "ForwardSocket": [ 104 | "{ADB}", 105 | "-s", 106 | "{ADB_SERIAL}", 107 | "forward", 108 | "tcp:{FOWARD_PORT}", 109 | "localabstract:{LOCAL_SOCKET}" 110 | ], 111 | "NetcatAddress": [ 112 | "{ADB}", 113 | "-s", 114 | "{ADB_SERIAL}", 115 | "shell", 116 | "cat /proc/net/arp | grep : " 117 | ], 118 | "ScreencapRawByNetcat": [ 119 | "{ADB}", 120 | "-s", 121 | "{ADB_SERIAL}", 122 | "exec-out", 123 | "screencap | nc -w 3 {NETCAT_ADDRESS} {NETCAT_PORT}" 124 | ], 125 | "ScreencapRawWithGzip": [ 126 | "{ADB}", 127 | "-s", 128 | "{ADB_SERIAL}", 129 | "exec-out", 130 | "screencap | gzip -1" 131 | ], 132 | "ScreencapEncode": [ 133 | "{ADB}", 134 | "-s", 135 | "{ADB_SERIAL}", 136 | "exec-out", 137 | "screencap -p" 138 | ], 139 | "ScreencapEncodeToFile": [ 140 | "{ADB}", 141 | "-s", 142 | "{ADB_SERIAL}", 143 | "shell", 144 | "screencap -p > \"/data/local/tmp/{TEMP_FILE}\"" 145 | ], 146 | "PullFile": [ 147 | "{ADB}", 148 | "-s", 149 | "{ADB_SERIAL}", 150 | "pull", 151 | "/data/local/tmp/{TEMP_FILE}", 152 | "{DST_PATH}" 153 | ], 154 | "Abilist": [ 155 | "{ADB}", 156 | "-s", 157 | "{ADB_SERIAL}", 158 | "shell", 159 | "getprop ro.product.cpu.abilist | tr -d '\n\r'" 160 | ], 161 | "SDK": [ 162 | "{ADB}", 163 | "-s", 164 | "{ADB_SERIAL}", 165 | "shell", 166 | "getprop ro.build.version.sdk | tr -d '\n\r'" 167 | ], 168 | "Orientation": [ 169 | "{ADB}", 170 | "-s", 171 | "{ADB_SERIAL}", 172 | "shell", 173 | "dumpsys input | grep SurfaceOrientation | grep -m 1 -o -E [0-9]" 174 | ], 175 | "PushBin": [ 176 | "{ADB}", 177 | "-s", 178 | "{ADB_SERIAL}", 179 | "push", 180 | "{BIN_PATH}", 181 | "/data/local/tmp/{BIN_WORKING_FILE}" 182 | ], 183 | "ChmodBin": [ 184 | "{ADB}", 185 | "-s", 186 | "{ADB_SERIAL}", 187 | "shell", 188 | "chmod 700 \"/data/local/tmp/{BIN_WORKING_FILE}\"" 189 | ], 190 | "InvokeBin": [ 191 | "{ADB}", 192 | "-s", 193 | "{ADB_SERIAL}", 194 | "exec-out", 195 | "export LD_LIBRARY_PATH=/data/local/tmp/; \"/data/local/tmp/{BIN_WORKING_FILE}\" {BIN_EXTRA_PARAMS}" 196 | ], 197 | "InvokeApp": [ 198 | "{ADB}", 199 | "-s", 200 | "{ADB_SERIAL}", 201 | "shell", 202 | "export CLASSPATH=\"/data/local/tmp/{APP_WORKING_FILE}\"; app_process /data/local/tmp {PACKAGE_NAME}" 203 | ] 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /assets/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/assets/logo.ico -------------------------------------------------------------------------------- /src/MBA.Cli/MBA.Cli.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | ..\..\assets\logo.ico 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/PublishProfiles/linux-arm64-single-cut.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | ARM64 8 | linux-arm64 9 | ..\..\Publish\MBA.Cli-linux-arm64-single-cut\ 10 | 11 | Release 12 | true 13 | true 14 | true 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/PublishProfiles/linux-x64-single-cut.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | x64 8 | linux-x64 9 | ..\..\Publish\MBA.Cli-linux-x64-single-cut\ 10 | 11 | Release 12 | true 13 | true 14 | true 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/PublishProfiles/osx-arm64-single-cut.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | ARM64 8 | osx-arm64 9 | ..\..\Publish\MBA.Cli-osx-arm64-single-cut\ 10 | 11 | Release 12 | true 13 | true 14 | true 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/PublishProfiles/osx-x64-single-cut.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | x64 8 | osx-x64 9 | ..\..\Publish\MBA.Cli-osx-x64-single-cut\ 10 | 11 | Release 12 | true 13 | true 14 | true 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/PublishProfiles/win-arm64-single-cut.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | ARM64 8 | win-arm64 9 | ..\..\Publish\MBA.Cli-win-arm64-single-cut\ 10 | 11 | Release 12 | true 13 | true 14 | true 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/PublishProfiles/win-x64-single-cut.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | x64 8 | win-x64 9 | ..\..\Publish\MBA.Cli-win-x64-single-cut\ 10 | 11 | Release 12 | true 13 | true 14 | true 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/PublishProfiles/win-x64-single-runtime-relied.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | x64 8 | win-x64 9 | ..\..\Publish\MBA.Cli-win-x64-single-runtime-relied\ 10 | 11 | Release 12 | false 13 | false 14 | true 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MBA.Cli/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "MBA.Cli": { 4 | "commandName": "Project", 5 | "commandLineArgs": "NoPause", 6 | "environmentVariables": { 7 | "MBA_ENVIRONMENT": "Debug" 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/MBA.Cli/packages.lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "dependencies": { 4 | "net7.0": { 5 | "Serilog": { 6 | "type": "Direct", 7 | "requested": "[3.0.1, )", 8 | "resolved": "3.0.1", 9 | "contentHash": "E4UmOQ++eNJax1laE+lws7E3zbhKgHsGJbO7ra0yE5smUh+5FfUPIKKBxM3MO1tK4sgpQke6/pLReDxIc/ggNw==" 10 | }, 11 | "Serilog.Sinks.Console": { 12 | "type": "Direct", 13 | "requested": "[4.1.0, )", 14 | "resolved": "4.1.0", 15 | "contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==", 16 | "dependencies": { 17 | "Serilog": "2.10.0" 18 | } 19 | }, 20 | "Serilog.Sinks.Debug": { 21 | "type": "Direct", 22 | "requested": "[2.0.0, )", 23 | "resolved": "2.0.0", 24 | "contentHash": "Y6g3OBJ4JzTyyw16fDqtFcQ41qQAydnEvEqmXjhwhgjsnG/FaJ8GUqF5ldsC/bVkK8KYmqrPhDO+tm4dF6xx4A==", 25 | "dependencies": { 26 | "Serilog": "2.10.0" 27 | } 28 | }, 29 | "Serilog.Sinks.File": { 30 | "type": "Direct", 31 | "requested": "[5.0.0, )", 32 | "resolved": "5.0.0", 33 | "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==", 34 | "dependencies": { 35 | "Serilog": "2.10.0" 36 | } 37 | }, 38 | "Maa.AgentBinary": { 39 | "type": "Transitive", 40 | "resolved": "1.0.0", 41 | "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" 42 | }, 43 | "Maa.Framework.Binding": { 44 | "type": "Transitive", 45 | "resolved": "1.4.0", 46 | "contentHash": "WODdI8FaiRdrfVtY8iuYuLsWcJ02Nf4AZsU89U4zw/08cdwI3SmlwZCRYtiNcUM/M7h9wSccuokdAxssIGd1mg==" 47 | }, 48 | "Maa.Framework.Binding.Native": { 49 | "type": "Transitive", 50 | "resolved": "1.4.0", 51 | "contentHash": "v5Fs+L0Aedg3ozD2ZTy61Q1/wOu/Ch2G0LYorygbY0Sz+1U97XcOf3oTF79T5rQKtyMMpqv+GA2LHmYoiWy6Gw==", 52 | "dependencies": { 53 | "Maa.Framework.Binding": "1.4.0", 54 | "Maa.Framework.Runtimes": "1.4.0" 55 | } 56 | }, 57 | "Maa.Framework.Runtimes": { 58 | "type": "Transitive", 59 | "resolved": "1.4.0", 60 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 61 | }, 62 | "mba.core": { 63 | "type": "Project", 64 | "dependencies": { 65 | "Maa.Framework": "[1.4.0, )", 66 | "Serilog": "[3.0.1, )", 67 | "Serilog.Sinks.Console": "[4.1.0, )", 68 | "Serilog.Sinks.Debug": "[2.0.0, )", 69 | "Serilog.Sinks.File": "[5.0.0, )" 70 | } 71 | }, 72 | "Maa.Framework": { 73 | "type": "CentralTransitive", 74 | "requested": "[1.4.0, )", 75 | "resolved": "1.4.0", 76 | "contentHash": "lDbbTkU06pjJPLChXaqE3vPeC1nfrU3wPkDvI32YD4HrNYZKpvl3LFNyF+6+vupbX4mRDsRge0KgKCiiEMljOw==", 77 | "dependencies": { 78 | "Maa.AgentBinary": "1.0.0", 79 | "Maa.Framework.Binding.Native": "1.4.0" 80 | } 81 | } 82 | }, 83 | "net7.0/linux-arm64": { 84 | "Maa.Framework.Runtimes": { 85 | "type": "Transitive", 86 | "resolved": "1.4.0", 87 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 88 | } 89 | }, 90 | "net7.0/linux-x64": { 91 | "Maa.Framework.Runtimes": { 92 | "type": "Transitive", 93 | "resolved": "1.4.0", 94 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 95 | } 96 | }, 97 | "net7.0/osx-arm64": { 98 | "Maa.Framework.Runtimes": { 99 | "type": "Transitive", 100 | "resolved": "1.4.0", 101 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 102 | } 103 | }, 104 | "net7.0/osx-x64": { 105 | "Maa.Framework.Runtimes": { 106 | "type": "Transitive", 107 | "resolved": "1.4.0", 108 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 109 | } 110 | }, 111 | "net7.0/win-arm64": { 112 | "Maa.Framework.Runtimes": { 113 | "type": "Transitive", 114 | "resolved": "1.4.0", 115 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 116 | } 117 | }, 118 | "net7.0/win-x64": { 119 | "Maa.Framework.Runtimes": { 120 | "type": "Transitive", 121 | "resolved": "1.4.0", 122 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 123 | } 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /src/MBA.Core/Data/Config.cs: -------------------------------------------------------------------------------- 1 | using MBA.Core.Enums; 2 | using MaaFramework.Binding; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace MBA.Core.Data; 6 | 7 | public class Config 8 | { 9 | public List Tasks { get; set; } = new() { TaskType.Daily }; 10 | public List TasksExcept { get; set; } = new() { }; 11 | public UIConfig UI { get; set; } = new(); 12 | public CoreConfig Core { get; set; } = new(); 13 | public GameConfig Game { get; set; } = new(); 14 | public DailyConfig Daily { get; set; } = new(); 15 | public WeeklyConfig Weekly { get; set; } = new(); 16 | public ConfigDocument Document { get; } = new(); 17 | } 18 | 19 | public class UIConfig 20 | { 21 | public string CurrentMBACoreVersion { get; set; } = "0.0.0"; 22 | public bool FirstStartUp { get; set; } = true; 23 | public bool DebugMode { get; set; } = false; 24 | public string Proxy { get; set; } = string.Empty; 25 | 26 | [JsonIgnore] 27 | public Uri? ProxyUri => string.IsNullOrEmpty(Proxy) 28 | ? null 29 | : new Uri(Proxy.Contains("://") ? Proxy : $"http://{Proxy}"); 30 | } 31 | 32 | public class CoreConfig 33 | { 34 | public string Adb { get; set; } = "adb"; 35 | public string AdbAddress { get; set; } = "127.0.0.1:5555"; 36 | public AdbControllerTypes Touch { get; set; } = AdbControllerTypes.InputPresetAdb; 37 | public AdbControllerTypes ScreenCap { get; set; } = AdbControllerTypes.ScreencapRawWithGzip; 38 | 39 | [JsonIgnore] 40 | public AdbControllerTypes ControlType => Touch | ScreenCap; 41 | } 42 | 43 | public class GameConfig 44 | { 45 | public GameLanguageServer Language { get; set; } = GameLanguageServer.EN; 46 | public GameLanguageServer Server { get; set; } = GameLanguageServer.TaiwanHongKongMacao; 47 | public string PackageEntry { get; set; } = string.Empty; 48 | 49 | [JsonIgnore] 50 | public GameLanguageServer LanguageServer => Language | Server; 51 | } 52 | 53 | public class DailyConfig 54 | { 55 | public int TacticalChallengeTimes { get; set; } = 5;/* 56 | public bool DailyNormalMissionDuringActivities { get; set; } = false; 57 | public string NormalMissionId { get; set; } = "0-0"; 58 | public int NormalMissionTimes { get; set; } = 17; 59 | public string HardMissionId { get; set; } = "H0-0"; 60 | public int HardMissionTimes { get; set; } = 3;*/ 61 | public Commissions CommissionsAllIn { get; set; } = Commissions.None; 62 | public int CommissionsBaseDefenseTimes { get; set; } = 1; 63 | public int CommissionsItemRetrievalTimes { get; set; } = 0; 64 | public Bounty BountyAllIn { get; set; } = Bounty.DesertRailroad; 65 | public int BountyOverpassTimes { get; set; } = 2; 66 | public int BountyDesertRailroadTimes { get; set; } = 2; 67 | public int BountyClassroomTimes { get; set; } = 2; 68 | public Scrimmage ScrimmageAllIn { get; set; } = Scrimmage.Trinity; 69 | public int ScrimmageTrinityTimes { get; set; } = 2; 70 | public int ScrimmageGehennaTimes { get; set; } = 2; 71 | public int ScrimmageMillenniumTimes { get; set; } = 2; 72 | } 73 | 74 | public class WeeklyConfig 75 | { 76 | 77 | } 78 | 79 | public class ConfigDocument 80 | { 81 | public string Tasks { get; } = $"要执行的任务, {(int)TaskType.Bounty}.{TaskType.Bounty} (悬赏通缉), {(int)TaskType.Cafe}.{TaskType.Cafe} (咖啡厅), {(int)TaskType.Club}.{TaskType.Club} (社团), {(int)TaskType.Commissions}.{TaskType.Commissions} (特殊任务), {/*(int)TaskType.Crafting}.{TaskType.Crafting*/" TODO"} (制造), {(int)TaskType.Mailbox}.{TaskType.Mailbox} (信箱), {(int)TaskType.Scrimmage}.{TaskType.Scrimmage} (学院交流会), {/*(int)TaskType.Shop}.{TaskType.Shop*/" TODO"} (商店), {(int)TaskType.TacticalChallenge}.{TaskType.TacticalChallenge} (战术大赛), {(int)TaskType.Tasks}.{TaskType.Tasks} (任务,日常周常奖励收菜), {(int)TaskType.StartUp}.{TaskType.StartUp} (只启动游戏), {(int)TaskType.Daily}.{TaskType.Daily} (做日常), {(int)TaskType.Weekly}.{TaskType.Weekly} (做周常)"; 82 | public string TasksExcept { get; } = $"要排除的任务 (高优先), 以下任务不可被排除: {(int)TaskType.Daily}.{TaskType.Daily}, {(int)TaskType.Weekly}.{TaskType.Weekly}, {(int)TaskType.StartUp}.{TaskType.StartUp}"; 83 | 84 | #region UIConfig 85 | 86 | public string FirstStartUp { get; } = "是否第一次启动"; 87 | public string DebugMode { get; } = "是否开启 Debug Mode (生成的文件会占用大量空间)"; 88 | public string Proxy { get; } = "代理地址,例如 http://127.0.0.1:7890"; 89 | 90 | #endregion 91 | 92 | #region CoreConfig 93 | 94 | public string Adb { get; } = "adb.exe 所在路径,相对绝对均可,例如 C:/adb.exe,不要有中文"; 95 | public string AdbAddress { get; } = "adb 连接地址,例如 127.0.0.1:5555"; 96 | public string Touch { get; } = $"点击方式:{AdbControllerTypes.InputPresetAdb}, {AdbControllerTypes.InputPresetMinitouch}, {AdbControllerTypes.InputPresetMaatouch}"; 97 | public string ScreenCap { get; } = $"截图方式:{AdbControllerTypes.ScreencapFastestWay}, {AdbControllerTypes.ScreencapRawByNetcat}, {AdbControllerTypes.ScreencapRawWithGzip}, {AdbControllerTypes.ScreencapEncode}, {AdbControllerTypes.ScreencapEncodeToFile}, {AdbControllerTypes.ScreencapMinicapDirect}, {AdbControllerTypes.ScreencapMinicapStream}"; 98 | 99 | #endregion 100 | 101 | #region GameConfig 102 | 103 | public string Language { get; } = $"游戏内语言:{GameLanguageServer.EN} (English), {GameLanguageServer.TC} (Traditional Chinese), {GameLanguageServer.SC} (Simplified Chinese)"; 104 | // $"游戏内语言:{GameLanguageServer.JP}, {GameLanguageServer.KR}, {GameLanguageServer.EN}, {GameLanguageServer.TH}, {GameLanguageServer.TC}, {GameLanguageServer.SC}"; 105 | public string Server { get; } = $"游戏服务器:{GameLanguageServer.Global}, {GameLanguageServer.Korea}, {GameLanguageServer.TaiwanHongKongMacao}, {GameLanguageServer.NorthAmerica}, {GameLanguageServer.Europe}, {GameLanguageServer.Asia}, {GameLanguageServer.Chinese}, {GameLanguageServer.YoStarCN}, {GameLanguageServer.Bilibili}, {GameLanguageServer.OthersCN}"; 106 | // $"游戏服务器:{GameLanguageServer.Japanese}, {GameLanguageServer.Global}, {GameLanguageServer.Korea}, {GameLanguageServer.TaiwanHongKongMacao}, {GameLanguageServer.NorthAmerica}, {GameLanguageServer.Europe}, {GameLanguageServer.Asia}, {GameLanguageServer.Chinese}, {GameLanguageServer.YoStarCN}, {GameLanguageServer.Bilibili}, {GameLanguageServer.Ourplay}, {GameLanguageServer.OthersCN}"; 107 | public string PackageEntry { get; set; } = "备用启动入口, 当 Language 和 Server 不匹配 或 Server 不支持时使用, 需要填入 activity, 例如 com.hypergryph.arknights/com.u8.sdk.U8UnityContext"; 108 | 109 | #endregion 110 | 111 | #region DailyConfig 112 | 113 | public string TacticalChallengeTimes { get; } = "日活打 JJC 的次数, 0 ~ 5, 0 为只领取信用点";/* 114 | public string NormalMissionId { get; } = "普通任务的 Id, 0-0 为打目前打到的一关"; 115 | public string NormalMissionTimes { get; } = "日活打普通任务的次数, > 0"; 116 | public string HardMissionId { get; } = "困难任务的 Id, H0-0 为打目前打到的一关"; 117 | public string HardMissionTimes { get; } = "日活打困难任务的次数, 1 ~ 3";*/ 118 | public string CommissionsAllIn { get; } = $"日活剩余的体力要执行的特殊任务, {(int)Commissions.None}.{Commissions.None} (不执行), {(int)Commissions.BaseDefense}.{Commissions.BaseDefense} (据点防御), {(int)Commissions.ItemRetrieval}.{Commissions.ItemRetrieval} (信用回收)"; 119 | public string CommissionsBaseDefenseTimes { get; } = "日活特殊任务打据点防御的次数"; 120 | public string CommissionsItemRetrievalTimes { get; } = "日活特殊任务打信用回收的次数"; 121 | public string BountyAllIn { get; } = $"(国服不可用) 日活剩余的票要执行的悬赏通缉, {(int)Bounty.None}.{Bounty.None} (不执行), {(int)Bounty.Overpass}.{Bounty.Overpass} (高架公路), {(int)Bounty.DesertRailroad}.{Bounty.DesertRailroad} (沙漠铁道), {(int)Bounty.Classroom}.{Bounty.Classroom} (教室)"; 122 | public string BountyOverpassTimes { get; } = "(国服不可用) 日活悬赏通缉打高架公路的次数"; 123 | public string BountyDesertRailroadTimes { get; } = "(国服不可用) 日活悬赏通缉打沙漠铁道的次数"; 124 | public string BountyClassroomTimes { get; } = "(国服不可用) 日活悬赏通缉打教室的次数"; 125 | public string ScrimmageAllIn { get; } = $"(国服不可用) 日活剩余的票要执行的悬赏通缉, {(int)Scrimmage.None}.{Scrimmage.None} (不执行), {(int)Scrimmage.Trinity}.{Scrimmage.Trinity} (三一), {(int)Scrimmage.Gehenna}.{Scrimmage.Gehenna} (格黑娜), {(int)Scrimmage.Millennium}.{Scrimmage.Millennium} (千年)"; 126 | public string ScrimmageTrinityTimes { get; } = "(国服不可用) 日活学院交流会打三一的次数"; 127 | public string ScrimmageGehennaTimes { get; } = "(国服不可用) 日活学院交流会打格黑娜的次数"; 128 | public string ScrimmageMillenniumTimes { get; } = "(国服不可用) 日活学院交流会打千年的次数"; 129 | 130 | #endregion 131 | } 132 | -------------------------------------------------------------------------------- /src/MBA.Core/Data/ConfigContext.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Encodings.Web; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace MBA.Core.Data; 5 | 6 | [JsonSerializable(typeof(Config))] 7 | public partial class ConfigContext : JsonSerializerContext 8 | { 9 | public static void InitOptions() 10 | { 11 | s_defaultOptions.WriteIndented = true; 12 | s_defaultOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; 13 | s_defaultOptions.Converters.Add(new JsonStringEnumConverter()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/MBA.Core/Data/DiffTasks.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Nodes; 2 | using MBA.Core.Extensions; 3 | 4 | namespace MBA.Core.Data; 5 | 6 | #pragma warning disable CA1507 // 使用 nameof 表达符号名称 7 | 8 | public class DiffTasks 9 | { 10 | private readonly Config _config; 11 | 12 | public DiffTasks(Config config) 13 | { 14 | _config = config; 15 | } 16 | 17 | public static JsonObject Empty => new(); 18 | 19 | #region Daily 20 | 21 | public JsonObject TacticalChallenge => 22 | _config.Daily.TacticalChallengeTimes.IsZeroTimes() 23 | ? TacticalChallenge0 24 | : TacticalChallenge1; 25 | private JsonObject TacticalChallenge0 => new() 26 | { 27 | ["diff_task"] = new JsonObject 28 | { 29 | ["Sub_Start_TacticalChallenge_Partial"] = new JsonObject 30 | { 31 | ["times_limit"] = ConfigTimesExtension.ZeroTimes 32 | }, 33 | ["Sub_End_TacticalChallenge_Partial"] = new JsonObject 34 | { 35 | ["times_limit"] = ConfigTimesExtension.ZeroTimes 36 | }, 37 | } 38 | }; 39 | private JsonObject TacticalChallenge1 => new() 40 | { 41 | ["diff_task"] = new JsonObject 42 | { 43 | ["Sub_Start_TacticalChallenge_Partial"] = new JsonObject 44 | { 45 | ["times_limit"] = _config.Daily.TacticalChallengeTimes.ClampTimes() 46 | }, 47 | } 48 | }; 49 | 50 | public JsonObject CommissionsGlobal => new() 51 | { 52 | ["enabled"] = _config.Daily.CommissionsAllIn != Enums.Commissions.None, 53 | ["diff_task"] = new JsonObject 54 | { 55 | ["Commissions"] = new JsonObject 56 | { 57 | ["next"] = _config.Daily.CommissionsAllIn.ToString() 58 | }, 59 | ["Click_PlusButton"] = new JsonObject 60 | { 61 | ["times_limit"] = ConfigTimesExtension.MaxTimes 62 | }, 63 | ["Click_MaxButton"] = new JsonObject 64 | { 65 | ["enabled"] = true 66 | }, 67 | } 68 | }; 69 | public JsonObject BaseDefense => new() 70 | { 71 | ["enabled"] = !_config.Daily.CommissionsBaseDefenseTimes.IsZeroTimes(), 72 | ["diff_task"] = new JsonObject 73 | { 74 | ["Click_PlusButton"] = new JsonObject 75 | { 76 | ["times_limit"] = _config.Daily.CommissionsBaseDefenseTimes.SubtractOnce() 77 | }, 78 | ["Click_MaxButton"] = new JsonObject 79 | { 80 | ["enabled"] = _config.Daily.CommissionsBaseDefenseTimes.IsMaxTimes() 81 | }, 82 | } 83 | }; 84 | public JsonObject ItemRetrieval => new() 85 | { 86 | ["enabled"] = !_config.Daily.CommissionsItemRetrievalTimes.IsZeroTimes(), 87 | ["diff_task"] = new JsonObject 88 | { 89 | ["Click_PlusButton"] = new JsonObject 90 | { 91 | ["times_limit"] = _config.Daily.CommissionsItemRetrievalTimes.SubtractOnce() 92 | }, 93 | ["Click_MaxButton"] = new JsonObject 94 | { 95 | ["enabled"] = _config.Daily.CommissionsItemRetrievalTimes.IsMaxTimes() 96 | }, 97 | } 98 | }; 99 | 100 | public JsonObject BountyGlobal => new() 101 | { 102 | ["enabled"] = _config.Daily.BountyAllIn != Enums.Bounty.None, 103 | ["diff_task"] = new JsonObject 104 | { 105 | ["BountyGlobal"] = new JsonObject 106 | { 107 | ["next"] = _config.Daily.BountyAllIn.ToString() 108 | }, 109 | ["Click_MaxButton"] = new JsonObject 110 | { 111 | ["enabled"] = true 112 | }, 113 | } 114 | }; 115 | public JsonObject Overpass => new() 116 | { 117 | ["enabled"] = !_config.Daily.BountyOverpassTimes.IsZeroTimes(), 118 | ["diff_task"] = new JsonObject 119 | { 120 | ["Click_PlusButton"] = new JsonObject 121 | { 122 | ["times_limit"] = _config.Daily.BountyOverpassTimes.SubtractOnce() 123 | } 124 | } 125 | }; 126 | public JsonObject DesertRailroad => new() 127 | { 128 | ["enabled"] = !_config.Daily.BountyDesertRailroadTimes.IsZeroTimes(), 129 | ["diff_task"] = new JsonObject 130 | { 131 | ["Click_PlusButton"] = new JsonObject 132 | { 133 | ["times_limit"] = _config.Daily.BountyDesertRailroadTimes.SubtractOnce() 134 | } 135 | } 136 | }; 137 | public JsonObject Classroom => new() 138 | { 139 | ["enabled"] = !_config.Daily.BountyClassroomTimes.IsZeroTimes(), 140 | ["diff_task"] = new JsonObject 141 | { 142 | ["Click_PlusButton"] = new JsonObject 143 | { 144 | ["times_limit"] = _config.Daily.BountyClassroomTimes.SubtractOnce() 145 | } 146 | } 147 | }; 148 | 149 | public JsonObject ScrimmageGlobal => new() 150 | { 151 | ["enabled"] = _config.Daily.ScrimmageAllIn != Enums.Scrimmage.None, 152 | ["diff_task"] = new JsonObject 153 | { 154 | ["ScrimmageGlobal"] = new JsonObject 155 | { 156 | ["next"] = _config.Daily.ScrimmageAllIn.ToString() 157 | }, 158 | ["Click_MaxButton"] = new JsonObject 159 | { 160 | ["enabled"] = true 161 | }, 162 | } 163 | }; 164 | public JsonObject Trinity => new() 165 | { 166 | ["enabled"] = !_config.Daily.ScrimmageTrinityTimes.IsZeroTimes(), 167 | ["diff_task"] = new JsonObject 168 | { 169 | ["Click_PlusButton"] = new JsonObject 170 | { 171 | ["times_limit"] = _config.Daily.ScrimmageTrinityTimes.SubtractOnce() 172 | } 173 | } 174 | }; 175 | public JsonObject Gehenna => new() 176 | { 177 | ["enabled"] = !_config.Daily.ScrimmageGehennaTimes.IsZeroTimes(), 178 | ["diff_task"] = new JsonObject 179 | { 180 | ["Click_PlusButton"] = new JsonObject 181 | { 182 | ["times_limit"] = _config.Daily.ScrimmageGehennaTimes.SubtractOnce() 183 | } 184 | } 185 | }; 186 | public JsonObject Millennium => new() 187 | { 188 | ["enabled"] = !_config.Daily.ScrimmageMillenniumTimes.IsZeroTimes(), 189 | ["diff_task"] = new JsonObject 190 | { 191 | ["Click_PlusButton"] = new JsonObject 192 | { 193 | ["times_limit"] = _config.Daily.ScrimmageMillenniumTimes.SubtractOnce() 194 | } 195 | } 196 | }; 197 | 198 | #endregion 199 | } 200 | -------------------------------------------------------------------------------- /src/MBA.Core/Data/GlobalInfo.cs: -------------------------------------------------------------------------------- 1 | namespace MBA.Core.Data; 2 | 3 | public static class GlobalInfo 4 | { 5 | private const string Config = "./config"; 6 | private const string ConfigFile = $"{Config}/config.json"; 7 | private const string Debug = "./debug"; 8 | private const string LogFile = $"{Debug}/mba.log"; 9 | private const string Cache = "./cache"; 10 | private const string Resource = "./Resource"; 11 | 12 | internal static readonly string ConfigFullPath = Path.GetFullPath(Config); 13 | internal static readonly string ConfigFileFullPath = Path.GetFullPath(ConfigFile); 14 | internal static readonly string DebugFullPath = Path.GetFullPath(Debug); 15 | internal static readonly string LogFileFullPath = Path.GetFullPath(LogFile); 16 | internal static readonly string CacheFullPath = Path.GetFullPath(Cache); 17 | internal static readonly string ResourceFullPath = Path.GetFullPath(Resource); 18 | 19 | 20 | private const string BaseResource = $"{Resource}/Base"; 21 | private const string AdbConfigFile = $"{Resource}/controller_config.json"; 22 | 23 | internal static readonly string BaseResourceFullPath = Path.GetFullPath(BaseResource); 24 | internal static readonly string AdbConfigFileFullPath = Path.GetFullPath(AdbConfigFile); 25 | 26 | public static bool IsCli { get; set; } 27 | } 28 | -------------------------------------------------------------------------------- /src/MBA.Core/Enums/Bounty.cs: -------------------------------------------------------------------------------- 1 | namespace MBA.Core.Enums; 2 | 3 | public enum Bounty 4 | { 5 | None = 0, 6 | 7 | Overpass = 1, 8 | DesertRailroad = 2, 9 | Classroom = 3, 10 | } 11 | -------------------------------------------------------------------------------- /src/MBA.Core/Enums/Commissions.cs: -------------------------------------------------------------------------------- 1 | namespace MBA.Core.Enums; 2 | 3 | public enum Commissions 4 | { 5 | None = 0, 6 | 7 | BaseDefense = 1, 8 | ItemRetrieval = 2 9 | } 10 | -------------------------------------------------------------------------------- /src/MBA.Core/Enums/GameLanguageServer.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using MBA.Core.Managers; 3 | using G = MBA.Core.Enums.GameLanguageServer; 4 | 5 | namespace MBA.Core.Enums; 6 | 7 | [Flags] 8 | public enum GameLanguageServer 9 | { 10 | None = 0, 11 | 12 | // A NonMask is a mask that not contains the Server and its Languages 13 | NonJPMask = ~(Japanese | JP), 14 | NonGLMask = ~(Global | KR | EN | TH | TC), 15 | NonCNMask = ~(Chinese | SC), 16 | LanguageMask = 0xFF, 17 | ServerMask = 0xFFFF << 8, 18 | 19 | // Language 20 | JP = 0x01, 21 | KR = 0x02, 22 | EN = 0x04, 23 | TH = 0x08, 24 | TC = 0x10, 25 | SC = 0x20, 26 | 27 | // Server 28 | Japanese 29 | = 0x01 << 8, 30 | 31 | Global 32 | = 0xFE << 8, 33 | Korea 34 | = 0x02 << 8, 35 | TaiwanHongKongMacao 36 | = 0x04 << 8, 37 | NorthAmerica 38 | = 0x08 << 8, 39 | Europe 40 | = 0x10 << 8, 41 | Asia 42 | = 0x20 << 8, 43 | 44 | Chinese 45 | = 0xF << 16, 46 | YoStarCN 47 | = 0x1 << 16, 48 | Bilibili 49 | = 0x2 << 16, 50 | Ourplay 51 | = 0x4 << 16, 52 | OthersCN 53 | = 0x8 << 16, 54 | } 55 | 56 | public static class GameLanguageServerExtensions 57 | { 58 | private static readonly string _packageEntryJapanese = Encoding.UTF8.GetString(Convert.FromBase64String("Y29tLllvc3RhckpQLkJsdWVBcmNoaXZlL2NvbS55b3N0YXJqcC5ibHVlYXJjaGl2ZS5NeFVuaXR5UGxheWVyQWN0aXZpdHk=")); 59 | private static readonly string _packageEntryGlobal = Encoding.UTF8.GetString(Convert.FromBase64String("Y29tLm5leG9uLmJsdWVhcmNoaXZlL2NvbS5uZXhvbi5ibHVlYXJjaGl2ZS5NeFVuaXR5UGxheWVyQWN0aXZpdHk=")); 60 | private static readonly string _packageEntryYoStarCN = Encoding.UTF8.GetString(Convert.FromBase64String("Y29tLlJvYW1pbmdTdGFyLkJsdWVBcmNoaXZlL2NvbS55b3N0YXIuc3VwZXJzZGsuYWN0aXZpdHkuWW9TdGFyU3BsYXNoQWN0aXZpdHk=")); 61 | private static readonly string _packageEntryBilibili = Encoding.UTF8.GetString(Convert.FromBase64String("Y29tLlJvYW1pbmdTdGFyLkJsdWVBcmNoaXZlLmJpbGliaWxpL2NvbS55b3N0YXIuc3VwZXJzZGsuYWN0aXZpdHkuWW9TdGFyU3BsYXNoQWN0aXZpdHk=")); 62 | 63 | public static string GetPackageEntry(this G type) 64 | => type.IsJapanese() ? _packageEntryJapanese 65 | : type.IsGlobal() ? _packageEntryGlobal 66 | : type.IsYoStarCN() ? _packageEntryYoStarCN 67 | : type.IsBilibili() ? _packageEntryBilibili 68 | : ConfigManager.Config.Game.PackageEntry; 69 | 70 | public static G GetLanguage(this G type) 71 | => type & G.LanguageMask; 72 | 73 | public static G GetServer(this G type) 74 | => type & G.ServerMask; 75 | 76 | public static bool IsValid(this G type) 77 | => type != G.None 78 | && type.GetServer() != G.None 79 | && type.GetLanguage() != G.None 80 | && (type.IsJapanese() || type.IsGlobal() || type.IsChinese()); 81 | 82 | // Used internally only, as there is no confirmation that the type is None 83 | 84 | internal static bool IsJapanese(this G type) 85 | => (type & G.NonJPMask) == G.None; 86 | 87 | internal static bool IsGlobal(this G type) 88 | => (type & G.NonGLMask) == G.None; 89 | 90 | internal static bool IsChinese(this G type) 91 | => (type & G.NonCNMask) == G.None; 92 | 93 | internal static bool IsYoStarCN(this G type) 94 | => type.IsChinese() && (type & G.YoStarCN) == G.YoStarCN; 95 | 96 | internal static bool IsBilibili(this G type) 97 | => type.IsChinese() && (type & G.Bilibili) == G.Bilibili; 98 | } 99 | -------------------------------------------------------------------------------- /src/MBA.Core/Enums/Scrimmage.cs: -------------------------------------------------------------------------------- 1 | namespace MBA.Core.Enums; 2 | 3 | public enum Scrimmage 4 | { 5 | None = 0, 6 | 7 | Trinity = 1, 8 | Gehenna = 2, 9 | Millennium = 3, 10 | } 11 | -------------------------------------------------------------------------------- /src/MBA.Core/Enums/TaskType.cs: -------------------------------------------------------------------------------- 1 | using MBA.Core.Data; 2 | using MBA.Core.Managers; 3 | 4 | namespace MBA.Core.Enums; 5 | 6 | /* 新增一个 TaskType 可能需要改动: 7 | * 1. this 添加 TaskType 8 | * 2. out 添加至 pipeline json 中 9 | * 3. this 添加 private static readonly List 10 | * 4. this 添加至 ToList 11 | * 5. this 添加至 TryRunTasks 中的 Replace 12 | * 6. out 添加至 DiffTasks 13 | * 7. this 添加至 EnableTask 中的 switch 14 | */ 15 | 16 | public enum TaskType 17 | { 18 | Bounty = 1, 19 | Cafe = 2, 20 | Club = 3, 21 | Commissions = 4, 22 | //Crafting = 5, 23 | Mailbox = 6, 24 | Scrimmage = 7, 25 | //Shop = 8, 26 | TacticalChallenge = 9, 27 | Tasks = 10, 28 | 29 | StartUp = 100, 30 | Daily = 101, 31 | Weekly = 102, 32 | 33 | // 以下任务不对用户公开,以保持可配置任务的统一 34 | Test = 0, 35 | 36 | BountyGlobal = -1_0, 37 | Overpass = -1_1, 38 | DesertRailroad = -1_2, 39 | Classroom = -1_3, 40 | BountyChinese = -1_9, 41 | 42 | CommissionsGlobal = -4_0, 43 | BaseDefense = -4_1, 44 | ItemRetrieval = -4_2, 45 | 46 | ScrimmageGlobal = -7_0, 47 | Trinity = -7_1, 48 | Gehenna = -7_2, 49 | Millennium = -7_3, 50 | ScrimmageChinese = -7_9, 51 | 52 | } 53 | 54 | public static class TaskTypeExtensions 55 | { 56 | private static Serilog.ILogger Log => LogManager.Logger; 57 | 58 | private static readonly List _dailyTasks = new() 59 | { 60 | TaskType.StartUp, 61 | //TaskType.Crafting, TODO 62 | TaskType.TacticalChallenge, 63 | TaskType.Bounty, 64 | TaskType.Club, 65 | TaskType.Mailbox, 66 | //TaskType.Shop, TODO 67 | TaskType.Cafe, 68 | TaskType.Tasks, 69 | TaskType.Commissions, 70 | TaskType.Scrimmage, 71 | TaskType.Tasks, 72 | }; 73 | 74 | private static readonly List _commissionsTasks = new() 75 | { 76 | TaskType.BaseDefense, 77 | TaskType.ItemRetrieval, 78 | TaskType.CommissionsGlobal 79 | }; 80 | 81 | private static readonly List _bountyGlobalTasks = new() 82 | { 83 | TaskType.Overpass, 84 | TaskType.DesertRailroad, 85 | TaskType.Classroom, 86 | TaskType.BountyGlobal, 87 | }; 88 | 89 | private static readonly List _bountyChineseTasks = new() 90 | { 91 | TaskType.BountyChinese 92 | }; 93 | 94 | private static readonly List _scrimmageGlobalTasks = new() 95 | { 96 | TaskType.Trinity, 97 | TaskType.Gehenna, 98 | TaskType.Millennium, 99 | TaskType.ScrimmageGlobal, 100 | }; 101 | 102 | private static readonly List _scrimmageChineseTasks = new() 103 | { 104 | // TaskType.ScrimmageChinese 105 | }; 106 | 107 | public static List ToList(this TaskType task, GameLanguageServer server) => task switch 108 | { 109 | TaskType.Daily => _dailyTasks, 110 | TaskType.Commissions => _commissionsTasks, 111 | TaskType.Bounty when server.IsChinese() => _bountyChineseTasks, 112 | TaskType.Bounty => _bountyGlobalTasks, 113 | TaskType.Scrimmage when server.IsChinese() => _scrimmageChineseTasks, 114 | TaskType.Scrimmage => _scrimmageGlobalTasks, 115 | _ => new List { task }, 116 | }; 117 | 118 | public static void Replace(this List tasks, GameLanguageServer server) 119 | { 120 | tasks.Replace(TaskType.Bounty, server) 121 | .Replace(TaskType.Commissions, server) 122 | .Replace(TaskType.Scrimmage, server); 123 | } 124 | 125 | public static bool Enabled(this TaskType task, DiffTasks diffTasks, out string diffTask) 126 | { 127 | var jsonObject = task switch 128 | { 129 | TaskType.TacticalChallenge => diffTasks.TacticalChallenge, 130 | 131 | TaskType.CommissionsGlobal => diffTasks.CommissionsGlobal, 132 | TaskType.BaseDefense => diffTasks.BaseDefense, 133 | TaskType.ItemRetrieval => diffTasks.ItemRetrieval, 134 | 135 | TaskType.BountyGlobal => diffTasks.BountyGlobal, 136 | TaskType.Overpass => diffTasks.Overpass, 137 | TaskType.DesertRailroad => diffTasks.DesertRailroad, 138 | TaskType.Classroom => diffTasks.Classroom, 139 | 140 | TaskType.ScrimmageGlobal => diffTasks.ScrimmageGlobal, 141 | TaskType.Trinity => diffTasks.Trinity, 142 | TaskType.Gehenna => diffTasks.Gehenna, 143 | TaskType.Millennium => diffTasks.Millennium, 144 | 145 | _ => DiffTasks.Empty, 146 | }; 147 | 148 | diffTask = jsonObject.ToJsonString(); 149 | Log.Debug("{task} Diff Task: {diff}.", task, diffTask); 150 | 151 | return (bool)(jsonObject["enabled"] ?? true); 152 | } 153 | 154 | public static List Replace(this List tasks, TaskType type, GameLanguageServer server) 155 | { 156 | int i = tasks.IndexOf(type); 157 | if (i >= 0) 158 | { 159 | tasks.RemoveAt(i); 160 | tasks.Replace(type, server); 161 | tasks.InsertRange(i, type.ToList(server)); 162 | } 163 | 164 | return tasks; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/MBA.Core/Extensions/ConfigTimesExtension.cs: -------------------------------------------------------------------------------- 1 | namespace MBA.Core.Extensions; 2 | 3 | internal static class ConfigTimesExtension 4 | { 5 | public static int ZeroTimes => 0; 6 | 7 | public static int MaxTimes => 99; 8 | 9 | public static int SubtractOnce(this int times) 10 | => (times - 1).ClampTimes(); 11 | 12 | public static int ClampTimes(this int times) 13 | => int.Clamp(times, ZeroTimes, MaxTimes); 14 | 15 | public static bool IsMaxTimes(this int times) 16 | => times >= MaxTimes; 17 | 18 | public static bool IsZeroTimes(this int times) 19 | => times <= ZeroTimes; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/MBA.Core/MBA.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PreserveNewest 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/MBA.Core/Maa.cs: -------------------------------------------------------------------------------- 1 | using MaaFramework.Binding; 2 | 3 | namespace MBA.Core; 4 | 5 | public class Maa 6 | { 7 | public static MaaToolkit Toolkit { get; } = new(); 8 | public static MaaUtility Utility { get; } = new(); 9 | } 10 | -------------------------------------------------------------------------------- /src/MBA.Core/Managers/ConfigManager.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Text.Json.Nodes; 3 | using MBA.Core.Data; 4 | 5 | namespace MBA.Core.Managers; 6 | 7 | public static class ConfigManager 8 | { 9 | private static Serilog.ILogger Log => LogManager.Logger; 10 | 11 | static ConfigManager() 12 | { 13 | ConfigContext.InitOptions(); 14 | InitConfig(); 15 | LogManager.ConfigureLogger(Config.UI.DebugMode, true); 16 | } 17 | 18 | private static readonly object _configWriteLock = new(); 19 | 20 | public static string AdbConfig { get; } = File.ReadAllText(GlobalInfo.AdbConfigFileFullPath); 21 | 22 | private static Config _config = new(); 23 | public static Config Config 24 | { 25 | get => _config; 26 | private set 27 | { 28 | if (_config != value) 29 | { 30 | _config = value; 31 | ConfigChanged?.Invoke(); 32 | } 33 | } 34 | } 35 | 36 | public delegate void ConfigChangedEventHandler(); 37 | public static event ConfigChangedEventHandler? ConfigChanged; 38 | 39 | internal static void InitConfig() 40 | { 41 | var location = $"{nameof(ConfigManager)}.{nameof(InitConfig)}"; 42 | 43 | TaskManager.RunTask(() => 44 | { 45 | var configDir = GlobalInfo.ConfigFullPath; 46 | var configFilePath = GlobalInfo.ConfigFileFullPath; 47 | if (!Directory.Exists(configDir)) 48 | _ = Directory.CreateDirectory(configDir); 49 | 50 | if (!File.Exists(configFilePath)) 51 | SaveConfig(); 52 | else 53 | LoadConfig(); 54 | }, 55 | location); 56 | } 57 | 58 | public static void LoadConfig() 59 | { 60 | var location = $"{nameof(ConfigManager)}.{nameof(LoadConfig)}"; 61 | 62 | TaskManager.RunTask(() => 63 | { 64 | Config = JsonSerializer.Deserialize( 65 | File.ReadAllText(GlobalInfo.ConfigFileFullPath), 66 | ConfigContext.Default.Config 67 | ) ?? Config; 68 | }, 69 | location); 70 | } 71 | 72 | public static void SaveConfig() 73 | { 74 | var location = $"{nameof(ConfigManager)}.{nameof(SaveConfig)}"; 75 | 76 | TaskManager.RunTask(() => 77 | { 78 | lock (_configWriteLock) 79 | { 80 | File.WriteAllText( 81 | GlobalInfo.ConfigFileFullPath, 82 | JsonSerializer.Serialize(Config, ConfigContext.Default.Config) 83 | ); 84 | } 85 | } 86 | , location); 87 | } 88 | 89 | public static void LogConfig() 90 | { 91 | var jsonObject = JsonNode.Parse( 92 | JsonSerializer.Serialize(Config, ConfigContext.Default.Config)) 93 | as JsonObject ?? new(); 94 | jsonObject.Remove(nameof(Config.Document)); 95 | jsonObject.Remove(nameof(Config.UI)); 96 | Log.Verbose("Native Config: {config}", jsonObject.ToString()); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/MBA.Core/Managers/LogManager.cs: -------------------------------------------------------------------------------- 1 | using MaaFramework.Binding; 2 | using MBA.Core.Data; 3 | using Serilog; 4 | using Serilog.Core; 5 | using Serilog.Events; 6 | 7 | namespace MBA.Core.Managers; 8 | 9 | public static class LogManager 10 | { 11 | public static ILogger Logger { get; private set; } = Serilog.Core.Logger.None; 12 | 13 | private static readonly LoggingLevelSwitch _levelSwitch = new(); 14 | 15 | static LogManager() 16 | { 17 | const string Template = "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}][{Level:u3}] {Message:lj}{NewLine}{Exception}"; 18 | var config = new LoggerConfiguration() 19 | .MinimumLevel.ControlledBy(_levelSwitch) 20 | .WriteTo.File( 21 | path: GlobalInfo.LogFileFullPath, 22 | outputTemplate: Template, 23 | // levelSwitch: LevelSwitch, 24 | restrictedToMinimumLevel: LogEventLevel.Verbose, 25 | rollingInterval: RollingInterval.Day, 26 | retainedFileCountLimit: 7); 27 | 28 | config = GlobalInfo.IsCli 29 | ? config.WriteTo.Console() 30 | : config.WriteTo.Debug(); 31 | 32 | Logger = config.CreateLogger(); 33 | Log.Logger = Logger; 34 | 35 | ConfigureLogger(true); 36 | } 37 | 38 | /// 39 | /// Configures the . 40 | /// 41 | /// Indicating whether degub mode is enabled or not. 42 | /// Indicating whether start infomation is logged or not. 43 | public static void ConfigureLogger(bool enableDebugMode, bool startLog = false) 44 | { 45 | // Information - 给用户看的信息 46 | // Debug - 给开发者看的信息 47 | // Verbose - 跟踪信息,开发者不怎么想看的那种 48 | 49 | var env = Environment.GetEnvironmentVariable("MBA_ENVIRONMENT") ?? "Empty"; 50 | enableDebugMode = enableDebugMode || env == "Debug"; 51 | SetFrameworkLog(enableDebugMode); 52 | 53 | if (enableDebugMode) 54 | _levelSwitch.MinimumLevel = LogEventLevel.Verbose; 55 | else 56 | _levelSwitch.MinimumLevel = LogEventLevel.Information; 57 | 58 | if (startLog) 59 | LogStart(env, enableDebugMode); 60 | } 61 | 62 | private static void SetFrameworkLog(bool enableDebugMode) 63 | { 64 | Maa.Utility.SetOption(GlobalOption.LogDir, GlobalInfo.DebugFullPath); 65 | Maa.Utility.SetOption(GlobalOption.SaveDraw, enableDebugMode); 66 | } 67 | 68 | private static bool _logStarted = false; 69 | 70 | private static void LogStart(string env, bool enableDebugMode) 71 | { 72 | if (_logStarted) return; 73 | _logStarted = true; 74 | 75 | Log.Information("==================================="); 76 | Log.Information(" MBA {UI} v{Version} started", GlobalInfo.IsCli ? "CLI" : "GUI", VersionManager.InformationalVersion); 77 | Log.Information(" Environment: {env}", env); 78 | Log.Information(" Debug Mode: {DebugMode}", enableDebugMode); 79 | /* Duplicate in famework log */ 80 | // Log.Information(" User Dir: {CurrentDirectory}", Directory.GetCurrentDirectory()); 81 | Log.Information("==================================="); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/MBA.Core/Managers/TaskManager.cs: -------------------------------------------------------------------------------- 1 | namespace MBA.Core.Managers; 2 | 3 | public static class TaskManager 4 | { 5 | private static Serilog.ILogger Log => LogManager.Logger; 6 | 7 | /// 8 | /// 执行任务, 并带有更好的日志显示 9 | /// 10 | /// 要执行的动作 11 | /// 日志显示名称 12 | /// 日志提示 13 | public static void RunTask( 14 | Action action, 15 | string name = nameof(Action), 16 | string prompt = ">>> ", 17 | bool catchException = true) 18 | { 19 | Log.Information("{prompt}Task {name} began.", prompt, name); 20 | 21 | if (catchException) 22 | { 23 | try 24 | { 25 | action.Invoke(); 26 | } 27 | catch (Exception e) 28 | { 29 | Log.Error(e, "{prompt}Task {name} failed.", prompt, name); 30 | } 31 | } 32 | else action(); 33 | 34 | Log.Information("{prompt}Task {name} done.", prompt, name); 35 | } 36 | 37 | /// 38 | /// 异步执行任务, 并带有更好的日志显示 39 | /// 40 | /// 要执行的动作 41 | /// 任务名称 42 | /// 日志提示 43 | public static async Task RunTaskAsync( 44 | Action action, 45 | string name = nameof(Action), 46 | string prompt = ">>> ", 47 | bool catchException = true) 48 | { 49 | Log.Information("{prompt}Async Task {name} began.", prompt, name); 50 | 51 | if (catchException) 52 | { 53 | try 54 | { 55 | await Task.Run(action); 56 | } 57 | catch (Exception e) 58 | { 59 | Log.Error(e, "{prompt}Async Task {name} failed: {e.Message}", prompt, name); 60 | } 61 | } 62 | else await Task.Run(action); 63 | 64 | Log.Information("{prompt}Async Task {name} done.", prompt, name); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/MBA.Core/Managers/VersionManager.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Http.Headers; 3 | using System.Reflection; 4 | using System.Text.Json.Nodes; 5 | using MBA.Core.Data; 6 | 7 | namespace MBA.Core.Managers; 8 | 9 | public static class VersionManager 10 | { 11 | private static Serilog.ILogger Log => LogManager.Logger; 12 | private static Config Config => ConfigManager.Config; 13 | 14 | public static string AssemblyVersion { get; private set; } 15 | public static string InformationalVersion { get; private set; } 16 | public static bool IsPreviewVersion { get; private set; } = false; 17 | public static bool Updated { get; private set; } = false; 18 | public static string ChangeLog { get; private set; } = ""; 19 | public static bool Released { get; private set; } = false; 20 | 21 | static VersionManager() 22 | { 23 | AssemblyVersion = GetAssemblyVersion(); 24 | InformationalVersion = GetInformationalVersion(); 25 | if (InformationalVersion.EndsWith("-dev") || InformationalVersion.Contains("Preview")) 26 | { 27 | IsPreviewVersion = true; 28 | } 29 | 30 | SetUpdatedAndChangeLog(); 31 | _ = SetReleasedAsync(); 32 | } 33 | 34 | private static string GetAssemblyVersion() 35 | { 36 | return Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) 37 | ?? ""; 38 | } 39 | 40 | private static string GetInformationalVersion() 41 | { 42 | var attr = Attribute.GetCustomAttribute( 43 | Assembly.GetExecutingAssembly(), 44 | typeof(AssemblyInformationalVersionAttribute)) 45 | as AssemblyInformationalVersionAttribute; 46 | return attr?.InformationalVersion 47 | ?? AssemblyVersion + "-"; 48 | } 49 | 50 | private static void SetUpdatedAndChangeLog() 51 | { 52 | if (Config.UI.CurrentMBACoreVersion == InformationalVersion) 53 | return; 54 | 55 | Config.UI.CurrentMBACoreVersion = InformationalVersion; 56 | if (IsPreviewVersion) 57 | return; 58 | 59 | Updated = true; 60 | try 61 | { 62 | var name = Assembly.GetExecutingAssembly().GetManifestResourceNames().First(x => x.Contains("CHANGELOG.md"))!; 63 | using var rs = Assembly.GetExecutingAssembly().GetManifestResourceStream(name)!; 64 | using StreamReader sr = new StreamReader(rs, detectEncodingFromByteOrderMarks: true); 65 | var changeLog = sr.ReadToEnd(); 66 | 67 | if (string.IsNullOrWhiteSpace(changeLog)) 68 | ChangeLog = ""; 69 | else 70 | ChangeLog = changeLog; 71 | } 72 | catch (Exception e) 73 | { 74 | Log.Warning("Failed to read ChangeLog: {Message}", e.Message); 75 | } 76 | } 77 | 78 | 79 | private static async Task SetReleasedAsync() 80 | { 81 | if (IsPreviewVersion) 82 | return; 83 | 84 | try 85 | { 86 | var latest = await GetLatestReleaseVersionAsync(); 87 | if (latest != AssemblyVersion && latest != InformationalVersion) 88 | { 89 | var url = "https://github.com/MaaAssistantArknights/MBA/releases/latest"; 90 | Released = true; 91 | Log.Information("New version released, available for download at {URL}.", url); 92 | } 93 | } 94 | catch (Exception e) 95 | { 96 | Log.Warning("VersionManager.{Func} failed: {Message}", 97 | nameof(GetLatestReleaseVersionAsync), 98 | e.Message); 99 | Log.Warning("Setting the {Proxy} in {Path} may be useful.", 100 | nameof(Config.UI.Proxy), 101 | GlobalInfo.ConfigFileFullPath); 102 | } 103 | } 104 | 105 | private static async Task GetLatestReleaseVersionAsync() 106 | { 107 | var url = "https://api.github.com/repos/MaaAssistantArknights/MBA/releases/latest"; 108 | var handler = new HttpClientHandler 109 | { 110 | AllowAutoRedirect = true, 111 | }; 112 | if (Config.UI.ProxyUri != null) 113 | { 114 | handler.UseProxy = true; 115 | handler.Proxy = new WebProxy 116 | { 117 | Address = Config.UI.ProxyUri, 118 | BypassProxyOnLocal = false, 119 | UseDefaultCredentials = false, 120 | }; 121 | } 122 | 123 | var client = new HttpClient(handler); 124 | client.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json"); 125 | client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); 126 | client.DefaultRequestHeaders.UserAgent.Add(ProductInfoHeaderValue.Parse("request")); 127 | var jsonString = await client.GetStringAsync(url); 128 | 129 | var jsonNode = JsonNode.Parse(jsonString); 130 | if (jsonNode == null) 131 | return string.Empty; 132 | 133 | jsonNode = jsonNode["tag_name"]; 134 | if (jsonNode == null) 135 | return string.Empty; 136 | 137 | var tag = jsonNode.ToString(); 138 | if (!tag.StartsWith('v')) 139 | return string.Empty; 140 | 141 | return tag.TrimStart('v'); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/MBA.Core/Sensei.cs: -------------------------------------------------------------------------------- 1 | using MaaFramework.Binding; 2 | using MBA.Core.Data; 3 | using MBA.Core.Enums; 4 | using MBA.Core.Managers; 5 | 6 | namespace MBA.Core; 7 | 8 | public class Sensei 9 | { 10 | private static Serilog.ILogger Log => LogManager.Logger; 11 | 12 | public static Sensei Agent { get; } = new(); 13 | 14 | // TODO: 去除静态 15 | private static Config Config { get; } = ConfigManager.Config; 16 | 17 | public void Start() 18 | { 19 | var location = $"{nameof(Sensei)}.{nameof(Start)}"; 20 | 21 | TaskManager.RunTask(() => 22 | { 23 | // remark: lock config 24 | ConfigManager.LogConfig(); 25 | 26 | using var maa = GetMaa(); 27 | var tasks = GetTasks(); 28 | if (!maa.Initialized) 29 | Log.Error("Failed to init Maa instance, a connection error or resource file corruption occurred, please refer to the log."); 30 | 31 | if (TryRunTasks(maa, tasks)) 32 | Log.Information("Congratulations! All tasks have been successful!"); 33 | else 34 | Log.Warning("Unfortunately, some tasks have failed..."); 35 | }, 36 | location); 37 | } 38 | 39 | private MaaInstance GetMaa() 40 | { 41 | var maa = new MaaInstance 42 | { 43 | Controller = new MaaAdbController(Config.Core.Adb, Config.Core.AdbAddress, Config.Core.ControlType, ConfigManager.AdbConfig, "./MaaAgentBinary"), 44 | Resource = new MaaResource(GlobalInfo.BaseResourceFullPath, $"{GlobalInfo.ResourceFullPath}/{Config.Game.Language}"), 45 | DisposeOptions = DisposeOptions.All, 46 | }; 47 | 48 | maa.Controller.SetOption( 49 | ControllerOption.DefaultAppPackageEntry, 50 | Config.Game.LanguageServer.GetPackageEntry()); 51 | 52 | return maa; 53 | } 54 | 55 | private List GetTasks() 56 | { 57 | var configTasks = new List(Config.Tasks); 58 | configTasks.Replace(TaskType.Daily, Config.Game.Server); 59 | configTasks.RemoveAll(Config.TasksExcept.Contains); 60 | return configTasks; 61 | } 62 | 63 | private bool TryRunTasks(MaaInstance maa, List tasks) 64 | { 65 | Log.Information("Task List: {list}.", tasks); 66 | tasks.Replace(Config.Game.Server); 67 | Log.Debug("Entry Task List: {list}.", tasks); 68 | 69 | var success = true; 70 | var failedTasks = new List(tasks.Count); 71 | var diffTasks = new DiffTasks(Config); 72 | 73 | foreach (TaskType task in tasks) 74 | { 75 | if (task.Enabled(diffTasks, out var diffTask)) 76 | { 77 | Log.Information("{task} Started.", task); 78 | } 79 | else 80 | { 81 | Log.Debug("{task} Skipped.", task); 82 | continue; 83 | } 84 | 85 | var status = maa.AppendTask(task.ToString(), diffTask) 86 | .Wait(); 87 | 88 | // TODO: MaaJob 和 MaaJobStatus 包含 任务名 及其参数 89 | 90 | if (status == MaaJobStatus.Success) 91 | { 92 | Log.Information("{task} Completed. Result: {status}", task, status); 93 | } 94 | else 95 | { 96 | success = false; 97 | failedTasks.Add(task); 98 | Log.Error("{task} Completed. Result: {status}", task, status); 99 | } 100 | } 101 | 102 | if (failedTasks.Any()) 103 | { 104 | Log.Warning("Failed task List: {failedTasks}", failedTasks); 105 | } 106 | return success; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/MBA.Core/packages.lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "dependencies": { 4 | "net7.0": { 5 | "Maa.Framework": { 6 | "type": "Direct", 7 | "requested": "[1.4.0, )", 8 | "resolved": "1.4.0", 9 | "contentHash": "lDbbTkU06pjJPLChXaqE3vPeC1nfrU3wPkDvI32YD4HrNYZKpvl3LFNyF+6+vupbX4mRDsRge0KgKCiiEMljOw==", 10 | "dependencies": { 11 | "Maa.AgentBinary": "1.0.0", 12 | "Maa.Framework.Binding.Native": "1.4.0" 13 | } 14 | }, 15 | "Serilog": { 16 | "type": "Direct", 17 | "requested": "[3.0.1, )", 18 | "resolved": "3.0.1", 19 | "contentHash": "E4UmOQ++eNJax1laE+lws7E3zbhKgHsGJbO7ra0yE5smUh+5FfUPIKKBxM3MO1tK4sgpQke6/pLReDxIc/ggNw==" 20 | }, 21 | "Serilog.Sinks.Console": { 22 | "type": "Direct", 23 | "requested": "[4.1.0, )", 24 | "resolved": "4.1.0", 25 | "contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==", 26 | "dependencies": { 27 | "Serilog": "2.10.0" 28 | } 29 | }, 30 | "Serilog.Sinks.Debug": { 31 | "type": "Direct", 32 | "requested": "[2.0.0, )", 33 | "resolved": "2.0.0", 34 | "contentHash": "Y6g3OBJ4JzTyyw16fDqtFcQ41qQAydnEvEqmXjhwhgjsnG/FaJ8GUqF5ldsC/bVkK8KYmqrPhDO+tm4dF6xx4A==", 35 | "dependencies": { 36 | "Serilog": "2.10.0" 37 | } 38 | }, 39 | "Serilog.Sinks.File": { 40 | "type": "Direct", 41 | "requested": "[5.0.0, )", 42 | "resolved": "5.0.0", 43 | "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==", 44 | "dependencies": { 45 | "Serilog": "2.10.0" 46 | } 47 | }, 48 | "Maa.AgentBinary": { 49 | "type": "Transitive", 50 | "resolved": "1.0.0", 51 | "contentHash": "09TsLd4LbaxoK68AZAg4MZFle/kkX8JZTbjRbkJYptyUCPCtdbVr8odukKG1CUzL4Wumbu+Fk7ppNX/OSlRMOA==" 52 | }, 53 | "Maa.Framework.Binding": { 54 | "type": "Transitive", 55 | "resolved": "1.4.0", 56 | "contentHash": "WODdI8FaiRdrfVtY8iuYuLsWcJ02Nf4AZsU89U4zw/08cdwI3SmlwZCRYtiNcUM/M7h9wSccuokdAxssIGd1mg==" 57 | }, 58 | "Maa.Framework.Binding.Native": { 59 | "type": "Transitive", 60 | "resolved": "1.4.0", 61 | "contentHash": "v5Fs+L0Aedg3ozD2ZTy61Q1/wOu/Ch2G0LYorygbY0Sz+1U97XcOf3oTF79T5rQKtyMMpqv+GA2LHmYoiWy6Gw==", 62 | "dependencies": { 63 | "Maa.Framework.Binding": "1.4.0", 64 | "Maa.Framework.Runtimes": "1.4.0" 65 | } 66 | }, 67 | "Maa.Framework.Runtimes": { 68 | "type": "Transitive", 69 | "resolved": "1.4.0", 70 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 71 | } 72 | }, 73 | "net7.0/linux-arm64": { 74 | "Maa.Framework.Runtimes": { 75 | "type": "Transitive", 76 | "resolved": "1.4.0", 77 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 78 | } 79 | }, 80 | "net7.0/linux-x64": { 81 | "Maa.Framework.Runtimes": { 82 | "type": "Transitive", 83 | "resolved": "1.4.0", 84 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 85 | } 86 | }, 87 | "net7.0/osx-arm64": { 88 | "Maa.Framework.Runtimes": { 89 | "type": "Transitive", 90 | "resolved": "1.4.0", 91 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 92 | } 93 | }, 94 | "net7.0/osx-x64": { 95 | "Maa.Framework.Runtimes": { 96 | "type": "Transitive", 97 | "resolved": "1.4.0", 98 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 99 | } 100 | }, 101 | "net7.0/win-arm64": { 102 | "Maa.Framework.Runtimes": { 103 | "type": "Transitive", 104 | "resolved": "1.4.0", 105 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 106 | } 107 | }, 108 | "net7.0/win-x64": { 109 | "Maa.Framework.Runtimes": { 110 | "type": "Transitive", 111 | "resolved": "1.4.0", 112 | "contentHash": "d3ihdTmR9IejyMb/e7gWfjZ6jRchZaJ5GicK4p0ipC1za2oZ2Ji6zW5bX477Li4c14AfuEvl7CPG72rX5ezO0g==" 113 | } 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /tools/ChangelogGenerator/.gitignore: -------------------------------------------------------------------------------- 1 | contributors.json 2 | -------------------------------------------------------------------------------- /tools/ChangelogGenerator/start.bat: -------------------------------------------------------------------------------- 1 | python changelog_generator.py 2 | pause -------------------------------------------------------------------------------- /tools/ImageCropper/README.md: -------------------------------------------------------------------------------- 1 | # 截图工具 2 | 3 | 本工具可以对 **预先准备好的截图** 或 **通过 ADB 连接设备**,进行 ROI 区域的截取、保存、取色操作。 4 | 5 | ## 环境 6 | 7 | 需要 `python` 环境 8 | 9 | ## 依赖 10 | 11 | ```shell 12 | python -m pip install -r requirements.txt 13 | ``` 14 | 15 | ## 使用 16 | 17 | 0. 根据 `MaaControllerSetOption` 的使用情况,调整脚本中的 `截图参数` 和 `初始窗口大小` 18 | 1. 如果有预先准备好的截图,需保存到 `./src/` 路径下 19 | 2. 运行 `start.bat` 或 `python main.py [device serial]` ,设备地址为可选 20 | - 根据提示 `Please select the device (ENTER to pass): ` ,选择 adb 已连接设备(按 ENTER 跳过选择) 21 | - 如果没有该提示,请使用 `python main.py [device serial]` 连接设备 22 | 3. 在弹窗中左键选择目标区域,滚轮缩放图片,右键移动图片 23 | 4. 使用快捷键操作: 24 | - 按 S ENTER 保存目标区域 25 | - 按 A 保存标准化截图 26 | - 按 R 不保存,只输出 ROI 范围 27 | - 按 C 不保存,输出 ROI 范围和 ColorMatch 的所需字段,大写将使用 connected 字段 28 | - 按 Z DELETE BACKSPACE 撤销 29 | - 按 0 ~ 9 缩放窗口 30 | - 按 Q ESC 退出 31 | - 按 任意键 跳过 / 刷新当前截图 32 | 33 | 5. 目标区域截图保存在 `./dst/` 路径下,文件名为 `src` 中的文件名 / 截图的时间 + ROI + 放大后的 ROI 34 | -------------------------------------------------------------------------------- /tools/ImageCropper/colormatcher.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | def kmeansClusterColors(img, method: int = -1, K: int = 3, criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)) -> list: 5 | ''' 6 | 将图片颜色类聚 7 | 8 | Args: 9 | img: 10 | 图片 11 | method: int = -1 12 | 颜色匹配方式。即 cv::ColorConversionCodes。可选,默认 4 (RGB)。 13 | 常用值:4 (RGB, 3 通道), 40 (HSV, 3 通道), 6 (GRAY, 1 通道)。 14 | 默认不进行转换。 15 | K: int = 3 16 | 颜色聚类个数 17 | criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2) 18 | K-means 参数,迭代停止的模式选择 19 | Return: 20 | [( center color, array([color, ...]), ... )] 21 | ''' 22 | if method >= 0: 23 | img = cv2.cvtColor(img, method) 24 | # 将图像数据转换为一维数组,保留颜色通道 25 | pixels = img.reshape((-1, img.shape[-1])) 26 | # 聚类 27 | _, labels, centers = cv2.kmeans(pixels.astype(np.float32), K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) 28 | # 将颜色值转换为原来的颜色通道类型 29 | centers = centers.astype(img.dtype) 30 | # __show(centers[labels.reshape(img.shape[:-1])]) 31 | # 返回结果 32 | ret = [] 33 | for i, center in enumerate(centers): 34 | colors = pixels[(labels == i).all(-1)] 35 | ret.append((center, colors)) 36 | return ret 37 | 38 | def getCount(img, lower, upper, connected: bool, method: int = -1) -> int: 39 | ''' 40 | 获取匹配成功的数量 41 | 42 | Args: 43 | img: 44 | 图片 45 | lower: 46 | 颜色下限值 47 | upper: 48 | 颜色上限值 49 | connected: bool 50 | 是否是相连的点才会被计数 51 | method: int = -1 52 | 颜色匹配方式。即 cv::ColorConversionCodes。可选,默认 4 (RGB)。 53 | 常用值:4 (RGB, 3 通道), 40 (HSV, 3 通道), 6 (GRAY, 1 通道)。 54 | 默认不进行转换。 55 | Return: 56 | int 57 | ''' 58 | # https://github.com/MaaAssistantArknights/MaaFramework/blob/main/source/MaaFramework/Vision/ColorMatcher.cpp 59 | # ColorMatcher::color_match 60 | if method >= 0: 61 | img = cv2.cvtColor(img, method) 62 | bin = cv2.inRange(img, np.array(lower, img.dtype), np.array(upper, img.dtype)) 63 | # __show(img) 64 | # __show(bin) 65 | if connected: 66 | return __count_non_zero_with_connected(bin) 67 | else: 68 | return cv2.countNonZero(bin) 69 | 70 | def __count_non_zero_with_connected(bin): 71 | number, labels, stats, centroids = cv2.connectedComponentsWithStats(bin, connectivity=8, ltype=cv2.CV_16U) 72 | count = 0 73 | for i in range(1, number): 74 | x = stats[i][cv2.CC_STAT_LEFT] 75 | y = stats[i][cv2.CC_STAT_TOP] 76 | width = stats[i][cv2.CC_STAT_WIDTH] 77 | height = stats[i][cv2.CC_STAT_HEIGHT] 78 | count = max(count, cv2.countNonZero(bin[ 79 | int(y): int(y + height), 80 | int(x): int(x + width) 81 | ])) 82 | return count 83 | 84 | def showClusterColors(cluster_colors): 85 | '''debug用''' 86 | for center, colors in cluster_colors: 87 | # 创建一个用于显示颜色的图像 88 | img = np.zeros((100, len(colors), 3), dtype=np.uint8) 89 | # 填充颜色 90 | img[:50, :] = center 91 | for i, color in enumerate(colors): 92 | img[50:, i] = color 93 | # 显示图像 94 | __show(img) 95 | 96 | def __show(img): 97 | '''debug用''' 98 | cv2.imshow('debug show', img) 99 | cv2.waitKey(0) 100 | cv2.destroyAllWindows() 101 | 102 | def __getBoxPlotValues(img, threshold: float = 1.5): 103 | '''return: minimum, lower quartile, median, upper quartile, maximum''' 104 | channel = img.shape[-1] 105 | colors = img.reshape((-1, channel)) 106 | ret = ([], [], [], [], []) 107 | for i in range(channel): 108 | ccs = colors[:, i] 109 | # 计算各项数据 110 | q1 = np.percentile(ccs, 25) 111 | q2 = np.percentile(ccs, 50) 112 | q3 = np.percentile(ccs, 75) 113 | # 计算上下边界 114 | iqr = q3 - q1 115 | lower_bound = q1 - iqr * threshold 116 | upper_bound = q3 + iqr * threshold 117 | # 排除异常值 118 | q0 = max(ccs.min(), lower_bound) 119 | q4 = min(ccs.max(), upper_bound) 120 | # 返回结果 121 | ret[0].append(q0.astype(img.dtype)) 122 | ret[1].append(q1.astype(img.dtype)) 123 | ret[2].append(q2.astype(img.dtype)) 124 | ret[3].append(q3.astype(img.dtype)) 125 | ret[4].append(q4.astype(img.dtype)) 126 | return ret 127 | 128 | # 简易方法 129 | def Simple(cluster_colors) -> list[tuple[list[int]]]: 130 | ''' 131 | 基于四分位数的一种简易匹配方法 132 | 133 | Args: 134 | cluster_colors 135 | 方法 clusterColors() 返回的结果 136 | 137 | Return: 138 | [(center, lower, upper), ...] 139 | ''' 140 | ret = [] 141 | for center, colors in cluster_colors: 142 | _, lower, _, upper, _ = __getBoxPlotValues(colors) 143 | ret.append((list(center), list(lower), list(upper))) 144 | return ret 145 | 146 | def RGBDistance(cluster_colors, threshold: int = 50) -> list[tuple[list[int]]]: 147 | ''' 148 | 基于 RGB 通道的一种加权欧式距离匹配方法 149 | 150 | Args: 151 | cluster_colors 152 | 方法 clusterColors() 返回的结果 153 | threshold: int = 50 154 | 阈值 0 - 765 (255 * 3) 155 | 156 | Return: 157 | [(center, lower, upper), ...] 158 | ''' 159 | # https://www.compuphase.com/cmetric.htm 160 | ret = [] 161 | for center, colors in cluster_colors: 162 | center = center.astype(np.int32) 163 | colors = colors.astype(np.int32) 164 | rmean = ((colors[:, 0] + center[0]) / 2).astype(np.int32) 165 | r = colors[:, 0] - center[0] 166 | g = colors[:, 1] - center[1] 167 | b = colors[:, 2] - center[2] 168 | distances = np.sqrt((((512+rmean)*r**2)>>8) + 4*g**2 + (((767-rmean)*b**2)>>8)) 169 | matched = colors[distances < threshold] 170 | lower, _, _, _, upper = __getBoxPlotValues(matched) 171 | ret.append((list(center), list(lower), list(upper))) 172 | return ret 173 | -------------------------------------------------------------------------------- /tools/ImageCropper/dst/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/tools/ImageCropper/dst/.gitkeep -------------------------------------------------------------------------------- /tools/ImageCropper/requirements.txt: -------------------------------------------------------------------------------- 1 | adbutils~=1.2.15 2 | opencv_python~=4.8.1.78 3 | -------------------------------------------------------------------------------- /tools/ImageCropper/roi.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | # 描述符基类,用于类型检查 4 | class Typed(object): 5 | 6 | def __init__(self, name, expected_type): 7 | self.name = name 8 | self.expected_type = expected_type 9 | 10 | def __get__(self, instance, cls): 11 | if instance is None: 12 | return self 13 | else: 14 | return instance.__dict__[self.name] 15 | 16 | def __set__(self, instance, value): 17 | if not isinstance(value, self.expected_type): 18 | raise TypeError("Expected " + str(self.expected_type)) 19 | instance.__dict__[self.name] = value 20 | 21 | def __delete__(self, instance): 22 | del instance.__dict__[self.name] 23 | 24 | #类装饰器,用来装饰自定义的类, 且将类属性设置为某特定类型的Typed实例 25 | def typeassert(**kwargs): 26 | def decorate(cls): 27 | for name, expected_type in kwargs.items(): 28 | # 将名字name和期望类型创建一个Typed实例 29 | iTyped = Typed(name, expected_type) 30 | # 将名字name和iType,设置到cls中,作为对应cls.__dict__中的key,value 31 | setattr(cls, name, iTyped) 32 | return cls 33 | return decorate 34 | 35 | @typeassert(width=float|int, height=float|int, x=float|int, y=float|int, zoom=float|int) 36 | class Roi(object): 37 | def __init__(self, width: float, height: float, x: float = 0 , y: float = 0, parent: Roi = None, zoom: float = 1) -> None: 38 | '''感兴趣区域 39 | 40 | 相对于父 Roi,由宽、高、左上角顶点坐标所描述的一个感兴趣区域 41 | 42 | Args: 43 | width: float 44 | Roi 的长度,当值 <= 0 且不为根 Roi 时,自动计算为 parent.width - x 45 | height: float 46 | Roi 的高度,当值 <= 0 且不为根 Roi 时,自动计算为 parent.height - y 47 | x: float = 0 48 | Roi 左上角顶点的 x 坐标,当值小于 0 时,置为0 49 | y: float = 0 50 | Roi 左上角顶点的 y 坐标,当值小于 0 时,置为0 51 | parent: Roi = None 52 | Roi 的父 Roi 53 | zoom: float = 1 54 | 缩放倍数(标记宽、高、左上角顶点坐标相对父 Roi 的倍数) 55 | 使用 getZoomRoi 获得经过缩放后的 Roi 56 | 57 | Returns: 58 | Roi 59 | ''' 60 | self.x = x 61 | self.y = y 62 | self.width = width 63 | self.height = height 64 | self.zoom = zoom # 加了缩放系数之后,就开始烧脑了( 65 | self.__parent = parent 66 | self.__check() 67 | 68 | def __check(self) -> None: 69 | if self.isRoot: 70 | assert self.x == 0, self.x 71 | assert self.y == 0, self.y 72 | assert self.width > 0, self.width 73 | assert self.height > 0, self.height 74 | assert self.zoom == 1, self.zoom 75 | return 76 | self.x = max(0, min(self.x, self.parent.width * self.zoom - 1)) 77 | self.y = max(0, min(self.y, self.parent.height * self.zoom - 1)) 78 | if self.width <= 0: 79 | self.width = self.parent.width * self.zoom - self.x 80 | assert self.width > 0, self.width 81 | if self.x + self.width > self.parent.width * self.zoom: 82 | self.width = min(self.width, self.parent.width * self.zoom) 83 | self.x = self.parent.width * self.zoom - self.width 84 | assert self.x >= 0, self.x 85 | if self.height <= 0: 86 | self.height = self.parent.height * self.zoom - self.y 87 | assert self.height > 0, self.height 88 | if self.y + self.height > self.parent.height * self.zoom: 89 | self.height = min(self.height, self.parent.height * self.zoom) 90 | self.y = self.parent.height * self.zoom - self.height 91 | assert self.y >= 0, self.y 92 | 93 | @property 94 | def parent(self) -> Roi: 95 | '''Roi 父节点''' 96 | return self.__parent 97 | 98 | @property 99 | def isRoot(self) -> bool: 100 | '''是否是根节点''' 101 | return self.parent is None 102 | 103 | @property 104 | def point(self) -> tuple[int, int]: 105 | '''Roi 左上角顶点坐标 (x, y)''' 106 | return (int(self.x), int(self.y)) 107 | 108 | @property 109 | def size(self) -> tuple[int, int]: 110 | '''Roi 大小 (width, height)''' 111 | return (int(self.width), int(self.height)) 112 | 113 | @property 114 | def rectangle(self) -> list[int]: 115 | '''Roi 区域 [ x, y, width, height ],由左上角顶点 (x, y) 和宽高描述''' 116 | return [int(self.x), int(self.y), int(self.width), int(self.height)] 117 | 118 | @property 119 | def rectanglePoints(self) -> tuple[tuple[int, int], tuple[int, int]]: 120 | '''Roi 区域 ( x1, y1, x2, y2 ),由左上角顶点 (x1, y1) 和右下角顶点 (x2, y2) 描述''' 121 | return ((int(self.x), int(self.y)), (int(self.x + self.width - 1), int(self.y + self.height - 1))) 122 | 123 | def getZoomRoi(self, zoom: float) -> Roi: 124 | ''' 125 | 获取相对于 parent,基于当前Roi,从 zoom 放大的一个新 Roi 126 | 127 | 如果 self 为 root,则相对于 root 128 | 129 | Args: 130 | zoom: float 131 | 缩放倍数 132 | 133 | Returns: 134 | Roi 135 | ''' 136 | parent = self if self.isRoot else self.parent 137 | return self.__class__(self.width * zoom, self.height * zoom, self.x * zoom, self.y * zoom, parent, zoom) 138 | 139 | def getCropRoi(self, x: float, y: float) -> Roi: 140 | ''' 141 | 获取相对于 parent,基于当前Roi,从坐标计算的一个新 Roi 142 | 143 | 如果 self 为 root,则相对于 root 144 | 145 | Args: 146 | x: float 147 | x 轴坐标 148 | y: float 149 | y 轴坐标 150 | 151 | Returns: 152 | Roi 153 | ''' 154 | parent = self if self.isRoot else self.parent 155 | if x > self.x: 156 | width = 1 + x - self.x 157 | x = self.x 158 | else: 159 | width = 1 - x + self.x 160 | if y > self.y: 161 | height = 1 + y - self.y 162 | y = self.y 163 | else: 164 | height = 1 - y + self.y 165 | return self.__class__(width, height, x, y, parent, self.zoom) 166 | 167 | def getRoiFromParent(self) -> Roi: 168 | ''' 169 | 获取相对于 parent.parent,基于当前Roi,从父 Roi 坐标计算的一个新 Roi 170 | 171 | 若 self 为 root,则返回 self 172 | 173 | Returns: 174 | Roi 175 | ''' 176 | if self.isRoot: 177 | return self 178 | if self.parent.isRoot and self.zoom == 1.0: 179 | return self 180 | x, y = self.parent.point 181 | p = self.parent if self.parent.isRoot else self.parent.parent 182 | return self.__class__(self.width / self.zoom, self.height / self.zoom, x + self.x / self.zoom, y + self.y / self.zoom, p, self.parent.zoom) 183 | 184 | def getRoiInRoot(self) -> Roi: 185 | ''' 186 | 获取相对于 root,基于 self,从 root 坐标计算的一个新 Roi 187 | 188 | 若 self 为 root,则返回 self 189 | 190 | Returns: 191 | Roi 192 | ''' 193 | roi = self.getRoiFromParent() 194 | return self if self is roi else roi.getRoiInRoot() 195 | 196 | def copy(self, parent: Roi = None, zoom: float = None) -> Roi: 197 | ''' 198 | 深复制 Roi 199 | 200 | Args: 201 | parent: Roi = None 202 | 父节点 203 | zoom: float = None 204 | 缩放倍数 205 | 206 | Returns: 207 | Roi 208 | ''' 209 | parent = self.parent if parent is None else parent 210 | zoom = self.zoom if zoom is None else zoom 211 | return self.__class__(self.width, self.height, self.x, self.y, parent, zoom) 212 | -------------------------------------------------------------------------------- /tools/ImageCropper/roimage.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from numpy import ndarray 4 | from roi import Roi 5 | import cv2 6 | 7 | class Roimage(Roi): 8 | def __init__(self, width: float, height: float, x: float = 0 , y: float = 0, parent: Roimage = None, zoom: float = 1) -> None: 9 | Roi.__init__(self, width, height, x, y, parent, zoom) 10 | self.__image: ndarray | None = None 11 | self.zoom_image_cache = {} 12 | 13 | @property 14 | def image(self): 15 | ''' 16 | 获取当前 Roi 的图片,如果没有则从父 Roi 裁剪 17 | 18 | 或设置当前 Roi 的图片 19 | ''' 20 | if self.__image is not None: 21 | return self.__image 22 | 23 | if self.zoom == 1: 24 | img = self.parent.image 25 | else: 26 | parent_img: ndarray = self.parent.image 27 | cache = self.parent.zoom_image_cache 28 | # 缓存过期 29 | if (parent_img != cache.get(self.parent.size)).any(): 30 | cache.clear() 31 | cache[self.parent.size] = parent_img.copy() 32 | # 命中缓存 33 | size = (int(self.parent.width * self.zoom), int(self.parent.height * self.zoom)) 34 | img = cache.get(size) 35 | # 没命中 36 | if img is None: 37 | img = cache.setdefault( 38 | size, 39 | cv2.resize(parent_img, size, interpolation=cv2.INTER_AREA)) 40 | return img[ 41 | int(self.y): int(self.y + self.height), 42 | int(self.x): int(self.x + self.width) 43 | ] 44 | 45 | @image.setter 46 | def image(self, value): 47 | self.__image = value 48 | -------------------------------------------------------------------------------- /tools/ImageCropper/src/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaaXYZ/MBA/3c0b2ef40a6de7ecf468889d67c079df73b52fc0/tools/ImageCropper/src/.gitkeep -------------------------------------------------------------------------------- /tools/ImageCropper/start.bat: -------------------------------------------------------------------------------- 1 | python main.py 2 | pause -------------------------------------------------------------------------------- /tools/ResourceReviewer/main.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 检查目标 3 | 1. 检查 Sub 型任务 4 | 必须含有键值对 "is_sub": true 5 | 2. 检查含有键值对 "is_sub": true 的任务 6 | 必须是 Sub 型任务 7 | 3. 检查含有键键值对 "recognition": "OCR" 的任务 8 | 必须含有键 "text" 9 | 4. 检查含有键 "text" 的任务 10 | (非通用资源)必须在 其他语言 资源中也含有 11 | (非通用资源)必须是 Partial 型任务 12 | 5. 检查含有键键值对 "recognition": "TemplateMatch" 的任务 13 | 必须含有键 "template" 14 | 6. 检查含有键 "template" 的任务 15 | (非通用资源)必须在 其他语言 资源中也含有 16 | (非通用资源)必须是 Partial 型任务 17 | 7. 检查 Base 和 其他语言 资源中的 Partial 型任务 18 | 必须互为拥有 19 | 8. 检查 Goto 型任务的父级任务 20 | next 必须含有 Sub_Wait_NowLoading_Partial 21 | 9. 检查 其他语言 资源中相同文件名的任务 22 | 必须和 EN 中相同文件名的任务一一对应 23 | ''' 24 | 25 | import os 26 | import sys 27 | import json 28 | 29 | pipeline_path = 'assets/Resource/{}/pipeline' 30 | base_tag = 'Base' 31 | lang_tags = ['EN', 'JP', 'KR', 'TH', 'TC', 'SC'] # 基准资源放第 0 位 32 | skip_key = 'skip_review' 33 | 34 | def load_json_files(directory: str) -> (dict, dict, bool): 35 | datas = {} 36 | merged_data = {} 37 | failed = False 38 | try: 39 | for filename in os.listdir(directory): 40 | if filename.endswith('.json'): 41 | path = f'{directory}/{filename}' 42 | with open(path, 'r', encoding='utf-8') as f: 43 | data = json.load(f) 44 | datas[path] = data # 将 path 和 data 添加到 datas 45 | merged_data.update(data) # 合并 data 46 | except Exception as e: 47 | print(f'::warning:: title=读取 {directory} 时出现错误::{e}') 48 | failed = True 49 | return (datas, merged_data, failed) 50 | 51 | def review_Sub(datas: dict) -> int: 52 | rule = 1 53 | print(f'::notice::Rule: {rule}') 54 | err = 0 55 | for path, data in datas.items(): 56 | for k, v in data.items(): 57 | if v.get(skip_key) == rule: 58 | continue 59 | if k.upper().startswith('SUB') and not v.get('is_sub'): 60 | print(f'::error file={path},title={k}::必须含有键值对 "is_sub": true') 61 | err += 1 62 | return err 63 | 64 | def review_is_sub(datas: dict) -> int: 65 | rule = 2 66 | print(f'::notice::Rule: {rule}') 67 | err = 0 68 | for path, data in datas.items(): 69 | for k, v in data.items(): 70 | if v.get(skip_key) == rule: 71 | continue 72 | if v.get('is_sub') and not k.upper().startswith('SUB'): 73 | print(f'::error file={path},title={k}::必须是 Sub 型任务') 74 | err += 1 75 | return err 76 | 77 | def review_OCR(datas: dict) -> int: 78 | rule = 3 79 | print(f'::notice::Rule: {rule}') 80 | err = 0 81 | for path, data in datas.items(): 82 | for k, v in data.items(): 83 | if v.get(skip_key) == rule: 84 | continue 85 | if v.get('recognition', '').upper() == 'OCR' and not v.get('text'): 86 | print(f'::error file={path},title={k}::必须含有键 "text"') 87 | err += 1 88 | return err 89 | 90 | def review_text(datas: dict, lang: dict, lang_tag: str) -> int: 91 | rule = 4 92 | print(f'::notice::Rule: {rule}') 93 | err = 0 94 | for path, data in datas.items(): 95 | for k, v in data.items(): 96 | if v.get(skip_key) == rule: 97 | continue 98 | if v.get('recognition', '').upper() != 'OCR': 99 | continue 100 | if not k.upper().endswith('PARTIAL'): 101 | print(f'::error file={path},title={k}::必须是 Partial 型任务') 102 | err += 1 103 | if not lang.get(k): 104 | print(f'::error file={path},title={k}::必须在 {lang_tag} 资源中也含有任务') 105 | print(f'::error file={path},title={k}::必须在 {lang_tag} 资源中也含有键 "text"') 106 | err += 2 107 | elif lang[k].get(skip_key) == rule: 108 | continue 109 | elif not lang[k].get('text'): 110 | print(f'::error file={path},title={k}::必须在 {lang_tag} 资源中也含有键 "text"') 111 | err += 1 112 | return err 113 | 114 | def review_TemplateMatch(datas: dict) -> int: 115 | rule = 5 116 | print(f'::notice::Rule: {rule}') 117 | err = 0 118 | for path, data in datas.items(): 119 | for k, v in data.items(): 120 | if v.get(skip_key) == rule: 121 | continue 122 | if v.get('recognition', '').upper() == 'TEMPLATEMATCH' and not v.get('template'): 123 | print(f'::error file={path},title={k}::必须含有键 "template"') 124 | err += 1 125 | return err 126 | 127 | def review_template(datas: dict, lang: dict, lang_tag: str) -> int: 128 | rule = 6 129 | print(f'::notice::Rule: {rule}') 130 | err = 0 131 | for path, data in datas.items(): 132 | for k, v in data.items(): 133 | if v.get(skip_key) == rule: 134 | continue 135 | if v.get('recognition', '').upper() != 'TEMPLATEMATCH': 136 | continue 137 | if not k.upper().endswith('PARTIAL'): 138 | print(f'::error file={path},title={k}::必须是 Partial 型任务') 139 | err += 1 140 | if not lang.get(k): 141 | print(f'::error file={path},title={k}::必须在 {lang_tag} 资源中也含有任务') 142 | print(f'::error file={path},title={k}::必须在 {lang_tag} 资源中也含有键 "template"') 143 | err += 2 144 | elif lang[k].get(skip_key) == rule: 145 | continue 146 | elif not lang[k].get('template'): 147 | print(f'::error file={path},title={k}::必须在 {lang_tag} 资源中也含有键 "template"') 148 | err += 1 149 | return err 150 | 151 | def review_Partial(datas: dict, lang: dict, lang_tag: str) -> int: 152 | rule = 7 153 | print(f'::notice::Rule: {rule}') 154 | err = 0 155 | for path, data in datas.items(): 156 | for k, v in data.items(): 157 | if v.get(skip_key) == rule: 158 | continue 159 | if k.upper().endswith('PARTIAL') and not lang.get(k): 160 | print(f'::error file={path},title={k}::必须在 {lang_tag} 资源中也含有任务') 161 | err += 1 162 | return err 163 | 164 | def review_Goto(datas: dict) -> int: 165 | rule = 8 166 | print(f'::notice::Rule: {rule}') 167 | err = 0 168 | for path, data in datas.items(): 169 | for k, v in data.items(): 170 | if v.get(skip_key) == rule: 171 | continue 172 | for task in v.get("next", []): 173 | if task == 'Sub_Wait_NowLoading_Partial': 174 | break 175 | if 'GOTO' in task.upper(): 176 | print(f'::error file={path},title={k}::{task} 的前面必须含有 Sub_Wait_NowLoading_Partial') 177 | err += 1 178 | break 179 | return err 180 | 181 | def review_TaskName(datas: dict, langs: dict, lang_tag: str) -> int: 182 | rule = 9 183 | print(f'::notice::Rule: {rule}') 184 | err = 0 185 | same_filename_list = [] 186 | for path in datas: 187 | for lpath in langs: 188 | if os.path.basename(path) in lpath: 189 | same_filename_list.append((path, lpath)) 190 | for path, lpath in same_filename_list: 191 | tasks, ltasks = list(datas[path].keys()), list(langs[lpath].keys()) 192 | lentasks, lenltasks = len(tasks), len(ltasks) 193 | for i in range(min(lentasks, lenltasks)): 194 | task, ltask = tasks[i], ltasks[i] 195 | if task != ltask: 196 | print(f'::error file={lpath},title={ltask}::必须和 {lang_tag} 的任务 {task} 一一对应') 197 | err += 1 198 | break 199 | if lentasks != lenltasks: 200 | print(f'::error file={lpath},title=任务数量不一致::任务数量 {lenltasks} 必须和 {lang_tag} 的任务数量 {lentasks} 一致') 201 | err += 1 202 | return err 203 | 204 | review_Bases = [ 205 | review_Sub, # 1 206 | review_is_sub, # 2 207 | review_OCR, # 3 208 | review_TemplateMatch, # 5 209 | review_Goto, # 8 210 | ] 211 | 212 | review_Bases_in_Lang = [ 213 | review_text, # 4 214 | review_template, # 6 215 | review_Partial, #7 216 | ] 217 | 218 | review_Langs_in_Base = [ 219 | review_Partial, #7 220 | ] 221 | 222 | review_Basics_in_Langs = [ 223 | review_TaskName, #9 224 | ] 225 | 226 | ret = 0 227 | os.chdir('../../') 228 | 229 | Bases, Base, Failed = load_json_files(pipeline_path.format(base_tag)) 230 | if Failed: 231 | print(f'::error::读取 {base_tag} 失败') 232 | sys.exit(1) 233 | 234 | for review in review_Bases: 235 | ret += review(Bases) 236 | 237 | for lang_tag in lang_tags: 238 | Langs, Lang, Failed= load_json_files(pipeline_path.format(lang_tag)) 239 | if Failed: 240 | continue 241 | 242 | for review in review_Bases_in_Lang: 243 | ret += review(Bases, Lang, lang_tag) 244 | for review in review_Langs_in_Base: 245 | ret += review(Langs, Base, base_tag) 246 | 247 | if lang_tag is lang_tags[0]: 248 | Basics, Basic = Langs, Lang 249 | continue 250 | for review in review_Basics_in_Langs: 251 | ret += review(Basics, Langs, lang_tags[0]) 252 | 253 | print(f'::warning::sensei 还剩 {ret} 个错误就完成了 ٩(๑>◡<๑)۶ ') 254 | sys.exit(ret) 255 | --------------------------------------------------------------------------------