├── .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 |

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 |
--------------------------------------------------------------------------------