Compare commits

..

6 Commits

Author SHA1 Message Date
pre-commit-ci[bot]
8d434fb84c chore: Auto update by pre-commit hooks [skip changelog] 2025-05-19 14:38:02 +00:00
status102
8681039067 chore: 点剧情
bug好多,再想想
2025-05-19 22:36:33 +08:00
status102
dd36585b16 fix: 逻辑取反 2025-05-19 20:59:56 +08:00
pre-commit-ci[bot]
b58917c74b chore: Auto update by pre-commit hooks [skip changelog] 2025-05-19 06:55:01 +00:00
status102
633fe73993 feat: 自动战斗自动点击剧情 2025-05-19 14:52:16 +08:00
status102
aa46d668d1 fix: 关卡内教程降低暂停按钮亮度,导致无法识别 2025-05-19 12:45:38 +08:00
3200 changed files with 25989 additions and 242348 deletions

View File

@@ -4,7 +4,7 @@
"ghcr.io/devcontainers/features/python:1": {},
"ghcr.io/devcontainers/features/sshd:1": {}
},
"postCreateCommand": "sudo sh -ce 'wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 20'",
"postCreateCommand": "sudo sh -ce 'apt update && apt install g++-12 -y && echo export CC=gcc-12 CXX=g++-12 >> /etc/profile.d/set-compiler.sh'",
"customizations": {
"vscode": {
"extensions": ["llvm-vs-code-extensions.vscode-clangd", "DavidAnson.vscode-markdownlint"]

View File

@@ -5,18 +5,16 @@ body:
- type: checkboxes
id: checks
attributes:
label: 请确认自己完成了下列必选项之后再进行勾选,若未完成必选项或勾选了"我未仔细阅读"选项将视为自愿接受被直接关闭 Issue
label: 请确认自己完成了下列要求之后再进行勾选,若未完成但勾选将被直接关闭 Issue
options:
- label: 我理解 Issue 是用于反馈和解决问题的,而非吐槽评论区,将尽可能提供更多信息帮助问题解决
required: false
- label: 我未仔细阅读这些内容,只是一键已读[所有内容](/MaaAssistantArknights/MaaAssistantArknights/issues),并相信这不会影响问题的处理
required: false
required: true
- label: 我填写了简短且清晰明确的标题,以便开发者在翻阅 Issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等
required: false
- label: 我使用的是当前更新版本的最新版, 并已查看版本发布至今的 [更新内容](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/), [Pull Requests](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pulls) 中尚未发布的更新内容并未提及该 Bug 已被修复的情况
required: false
- label: 我已检查了 [常见问题](https://maa.plus/docs/zh-cn/manual/faq.html), [公告](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/7732), [活跃议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues), [已关闭议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed) 确认我的问题未被提及
required: false
required: true
- label: 我使用的是当前更新版本的最新版,且已查看版本发布至今的 [更新内容](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/) [Pull Requests](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pulls) 中尚未发布的更新内容并未提及该 Bug 已被修复的情况
required: true
- label: 我已检查了[常见问题](https://maa.plus/docs/zh-cn/manual/faq.html)[公告](/MaaAssistantArknights/MaaAssistantArknights/issues/7732)[活跃议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues)[已关闭议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed)确认我的问题未被提及
required: true
- type: textarea
id: describe
attributes:
@@ -56,7 +54,7 @@ body:
label: 配置信息
description: |
请说明操作系统及版本、模拟器品牌、模拟器分辨率、DPI、帧率
若正在使用 MuMu 或雷电 9请说明截图增强是否开启
若正在使用 MuMu 12 或雷电 9请说明截图增强是否开启
最后请说明 GPU 加速推理是否开启,若开启请提供 GPU 型号。
validations:
required: true

View File

@@ -5,18 +5,16 @@ body:
- type: checkboxes
id: checks
attributes:
label: 请确认自己完成了下列必选项之后再进行勾选,若未完成必选项或勾选了"我未仔细阅读"选项将视为自愿接受被直接关闭 Issue
label: 在提问之前...
options:
- label: 我基本确定这是一个新功能/建议,而不是遇到了 Bug不确定的话请附上日志
required: false
- label: 我未仔细阅读这些内容,只是一键已读[所有内容](/MaaAssistantArknights/MaaAssistantArknights/issues),并相信这不会影响问题的处理
required: false
- label: 我填写了简短且清晰明确的标题,以便开发者在翻阅 Issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等
required: false
- label: 使用的是当前更新版本的最新版, 并已查看版本发布至今的 [更新内容](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/), [Pull Requests](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pulls) 中尚未发布的更新内容,确认我的建议未被提及
required: false
- label: 已检查了 [常见问题](https://maa.plus/docs/zh-cn/manual/faq.html), [公告](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/7732), [活跃议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues), [已关闭议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed) 确认我的建议未被提及
required: false
required: true
- label: 基本确定这是一个新功能/建议,而不是遇到了 Bug不确定的话请附上日志
required: true
- label: 使用的是当前更新版本的最新版,且已查看版本发布至今的 [更新内容](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/) 和 [Pull Requests](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pulls) 中尚未发布的更新内容,确认我的建议未被提及
required: true
- label: 我已检查了 [公告](/MaaAssistantArknights/MaaAssistantArknights/issues/7732)、[活跃议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues)、[已关闭议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed),确认我的建议未被提及
required: true
- type: textarea
id: describe
attributes:

View File

@@ -8,17 +8,15 @@ body:
label: 在提问之前...
options:
- label: 我理解 Issue 是用于反馈和解决问题的,而非吐槽评论区,将尽可能提供更多信息帮助问题解决
required: false
required: true
- label: 我填写了简短且清晰明确的标题,以便开发者在翻阅 Issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等
required: false
required: true
- label: 我已检查了[公告](/MaaAssistantArknights/MaaAssistantArknights/issues/7732)、[活跃议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues)、[已关闭议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed),确认我的问题未被提及
required: false
- label: 我未仔细阅读这些内容,只是一键已读[所有内容](/MaaAssistantArknights/MaaAssistantArknights/issues),并相信这不会影响问题的处理
required: false
required: true
- label: 我正在使用最新的 MAA 公测版本和最新的官版雷电 9 模拟器
required: false
required: true
- label: 我已参考文档确定安装路径、实例编号填写正确,并确认在关闭截图增强模式后问题消失
required: false
required: true
- label: 我未开启高帧率,且模拟器帧数设置为 60
required: false
- type: textarea

View File

@@ -8,18 +8,16 @@ body:
label: 在提问之前...
options:
- label: 我理解 Issue 是用于反馈和解决问题的,而非吐槽评论区,将尽可能提供更多信息帮助问题解决
required: false
required: true
- label: 我填写了简短且清晰明确的标题,以便开发者在翻阅 Issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等
required: false
required: true
- label: 我已检查了[公告](/MaaAssistantArknights/MaaAssistantArknights/issues/7732)、[活跃议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues)、[已关闭议题](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed),确认我的问题未被提及
required: false
- label: 我未仔细阅读这些内容,只是一键已读[所有内容](/MaaAssistantArknights/MaaAssistantArknights/issues),并相信这不会影响问题的处理
required: false
required: true
- label: 我正在使用最新的 MAA 公测版本和最新的官版或方舟专版 MuMu 模拟器
required: false
required: true
- label: 我已参考文档确定安装路径、实例编号、屏幕编号填写正确,并确认在关闭截图增强模式后问题消失
required: false
- label: 我未开启动态帧率及后台保活,模拟器帧数为 60显存使用策略为“画面表现更好”
required: true
- label: 我未开启后台保活,模拟器帧数为 60显存使用策略为“画面表现更好”
required: false
- type: textarea
id: describe

View File

@@ -1,23 +1,24 @@
name: Bug Report (in English)
description: Recognition errors, operation abnormalities, connection errors, etc.
description: >-
Recognition errors, operation abnormalities,
connection errors, etc.
labels: ["bug"]
body:
- type: checkboxes
id: checks
attributes:
label: |
Please ensure that you have completed the required items before checking the boxes.
Issues with incomplete required items or with the 'I did not read carefully' option checked will be considered voluntary acceptance of direct closure.
label: Before raising the issue...
description: |
Please ensure that you have completed the requirements before checking the box.
Issues with the checkbox checked but not completed will be directly closed.
options:
- label: I understand that Issues are for feedback and problem solving, not trolling the comments section, and will provide as much information as possible to help solve the problem.
required: true
- label: I filled in a short, clear title so that developers could quickly identify the general problem when going through the issue list. Instead of "Some suggestions", "Stuck", etc.
required: true
- label: I am using the latest version of the current update version, and have reviewed the [update content](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/) released to date, [Pull Requests](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pulls) unreleased update content and there is no mention of the bug being fixed.
- label: I am using the latest version of the current update version and have reviewed both the [Unreleased changes](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/) and there is no mention of the bug being fixed.
required: true
- label: I have checked all the options without carefully reading the content and believe this will not affect issue resolution.
required: false
- label: I have reviewed the [FAQs](https://maa.plus/docs/en-us/manual/faq.html), [Announcement](/MaaAssistantArknights/MaaAssistantArknights/issues/7732), [Open Issues](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues), [Closed Issues](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed) to ensure that my issue has not been mentioned.
- label: I have reviewed the [FAQs](https://maa.plus/docs/en-us/manual/faq.html), [Announcement](/MaaAssistantArknights/MaaAssistantArknights/issues/7732), [Open Issue](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues), [Closed Issue](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed) to ensure that my issue/bug has not been mentioned.
required: true
- type: textarea
id: describe
@@ -42,7 +43,7 @@ body:
id: logs
attributes:
label: Log and config files
description: |
description: >-
**Please locate the Generate Support Payload button under MAA Settings -> Issue Report, click the button, and upload the generated zip file**
**Please drag and drop the full file in, not your own cuttings or copies; compress it before uploading if too large.**
@@ -58,7 +59,7 @@ body:
label: Configuration information
description: |
Please specify the operating system and version, emulator brand, emulator resolution, DPI, and frame rate;
If you are using MuMu or LDPlayer 9, please specify whether Screenshot Enhancement is enabled;
If you are using MuMu 12 or LDPlayer 9, please specify whether Screenshot Enhancement is enabled;
Finally, please specify whether GPU accelerated inference is enabled, and if so, provide the GPU model.
validations:
required: true
@@ -66,7 +67,7 @@ body:
id: screenshots
attributes:
label: Screenshots or recordings
description: |
description: >-
In the `debug` directory, within the functionally categorized folders,
there are some error images captured automatically.
If related to this issue, please upload them together.
@@ -83,13 +84,14 @@ body:
and their aspect ratio and resolution are inconsistent,
which makes it harder for us to debug.
If the file size is too large, you may compress it before uploading.
If the file siz is too large, you may compress it before uploading.
validations:
required: false
- type: textarea
id: others
attributes:
label: Anything else?
label: Anthing else?
description: |
Anything that will give us more insight into the problem you are having.
validations:

View File

@@ -5,19 +5,21 @@ body:
- type: checkboxes
id: checks
attributes:
label: |
Please ensure that you have completed the required items before checking the boxes.
Issues with incomplete required items or with the 'I did not read carefully' option checked will be considered voluntary acceptance of direct closure.
label: Before raising the issue...
options:
- label: I'm probably sure this is a new feature/suggestion and not a bug encountered (please attach logs if you're not sure).
- label: |
I filled in a short, clear title so that developers could quickly identify the general problem when going through the issue list.
Instead of "Some suggestions", "Stuck", etc.
required: true
- label: I filled in a short, clear title so that developers could quickly identify the general problem when going through the issue list. Instead of "Some suggestions", "Stuck", etc.
- label: |
I'm probably sure this is a new feature/suggestion and not a bug encountered (please attach logs if you're not sure).
required: true
- label: I am using the latest version of the current update version, and have reviewed the [update content](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/) released to date, [Pull Requests](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pulls) unreleased update content and there is no mention of this feature/suggestion being added.
- label: |
I am using the latest version of the current update version and have reviewed both the [Unreleased changes](https://github.com/MaaAssistantArknights/MaaAssistantArknights/commits/dev/) and the [Pull requests](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pulls),
but there is no mention of this feature/suggestion being added.
required: true
- label: I have checked all the options without carefully reading the content and believe this will not affect issue resolution.
required: false
- label: I have reviewed the [FAQs](https://maa.plus/docs/en-us/manual/faq.html), [Announcement](/MaaAssistantArknights/MaaAssistantArknights/issues/7732), [Open Issues](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues), [Closed Issues](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed) to ensure that my feature/suggestion has not been mentioned.
- label: |
I have reviewed the [Announcement](/MaaAssistantArknights/MaaAssistantArknights/issues/7732), [Open Issue](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues), [Closed Issue](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues?q=is%3Aissue%20state%3Aclosed) to ensure that my feature/suggestion has not been mentioned.
required: true
- type: textarea
id: describe

View File

@@ -7,8 +7,8 @@ updates:
commit-message:
prefix: ci
assignees:
- constrat
- AnnAngela
- Constrat
groups:
github-actions:
patterns:

View File

@@ -552,7 +552,7 @@ comments:
Your log did not upload successfully, please re-upload it."
mode: add
- name: Upload failed
regexes: "^[^`]*(`[^`]+`[^`]*)*(\\[Uploading[^\\]]*…\\]\\(\\)|<!-- Failed to upload|<!-- Uploading)"
regexes: "^[^`]*(`[^`]+`[^`]*)*\\[Uploading[^\\]]*…\\]\\(\\)"
content: "你有一些文件没有上传成功,请重新上传。\n\n\
You have some files that did not upload successfully, please re-upload them."
mode: add

View File

@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false # Needed to bypass protection rules in Push changes

View File

@@ -12,9 +12,9 @@ on:
- "src/**"
- "cmake/**"
- "CMakeLists.txt"
- "MAA.sln"
- ".github/workflows/ci.yml"
- "!**/*.md"
- "tools/maadeps-download.py"
pull_request:
branches:
- "dev"
@@ -24,8 +24,8 @@ on:
- "src/**"
- "cmake/**"
- "CMakeLists.txt"
- "MAA.sln"
- "!**/*.md"
- "tools/maadeps-download.py"
workflow_dispatch:
concurrency:
@@ -45,7 +45,7 @@ jobs:
prerelease: ${{ steps.set_pre.outputs.prerelease }}
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
path: temp
show-progress: false
@@ -90,7 +90,7 @@ jobs:
echo >> CHANGELOG.md
echo "**Full Changelog**: [$last_tag -> $this_tag](https://github.com/MaaAssistantArknights/MaaAssistantArknights/compare/${last_tag}...${this_tag})" >> CHANGELOG.md
echo >> CHANGELOG.md
echo "[已有 Mirror酱 CDK前往 Mirror酱 高速下载](https://mirrorchyan.com/zh/projects?rid=MAA&source=maagh-release)" >> CHANGELOG.md
echo "[已有 Mirror酱 CDK前往 Mirror酱 高速下载](https://mirrorchyan.com/zh/projects?rid=MAA)" >> CHANGELOG.md
- name: Upload changelog to Github
uses: actions/upload-artifact@v4
@@ -108,13 +108,18 @@ jobs:
needs: meta
strategy:
matrix:
arch: [arm64, x64]
fail-fast: false
include:
- msbuild_target: x64
lowercase_target: x64
- msbuild_target: ARM64
lowercase_target: arm64
env:
MAABUILDER_TARGET_PLATFORM: ${{ matrix.msbuild_target }}
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
@@ -122,35 +127,6 @@ jobs:
run: |
git submodule update --init --depth 1 3rdparty/EmulatorExtras
- name: Cache MaaDeps
id: cache-maadeps
uses: actions/cache@v4
with:
path: |
./MaaDeps
key: ${{ runner.os }}-${{ matrix.arch }}-maadeps-${{ hashFiles('./tools/maadeps-download.py') }}
- name: Bootstrap MaaDeps
if: steps.cache-maadeps.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 tools/maadeps-download.py ${{ matrix.arch }}-windows
- name: Config cmake
run: |
mkdir -p build
cmake -B build ${{ matrix.arch == 'arm64' && '-A ARM64' }} -DCMAKE_BUILD_TYPE=Release -DMAADEPS_TRIPLET='maa-${{ matrix.arch }}-windows' -DINSTALL_RESOURCE=ON -DINSTALL_PYTHON=ON -DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}' -DBUILD_WPF_GUI=OFF
- name: Build
run: |
cmake --build build --config Release --parallel $env:NUMBER_OF_PROCESSORS
- name: Install
run: |
mkdir -p install
cmake --install build --prefix install --config Release
- name: Cache .nuke/temp, ~/.nuget/packages
id: cache-nuget
uses: actions/cache@v4
@@ -158,13 +134,38 @@ jobs:
path: |
.nuke/temp
~/.nuget/packages
key: ${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('**/*.csproj') }}
key: ${{ runner.os }}-${{ matrix.msbuild_target }}-${{ hashFiles('**/global.json', '**/*.csproj') }}
- name: Restore dependencies
if: steps.cache-nuget.outputs.cache-hit != 'true'
run: dotnet restore src/MaaWpfGui/MaaWpfGui.csproj
run: dotnet restore
- name: Taggify Version for csproj
- name: Cache MaaDeps
id: cache-maadeps
uses: actions/cache@v4
with:
path: |
./MaaDeps
key: ${{ runner.os }}-${{ matrix.lowercase_target }}-maadeps-${{ hashFiles('./maadeps-download.py') }}
- name: Bootstrap MaaDeps
if: steps.cache-maadeps.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 maadeps-download.py ${{ matrix.lowercase_target }}-windows
- name: Create fake event file
shell: bash
run: cp -v "$GITHUB_EVENT_PATH" ./event.json
- name: Merge Event Data with Inputs
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
run: |
cat "$GITHUB_EVENT_PATH" | jq '. + { "inputs": {"ReleaseSimulation": "${{ needs.meta.outputs.tag }}"} }' | tee ./event.json
- name: Taggify Version
run: |
$csprojPath = "src/MaaWpfGui/MaaWpfGui.csproj"
$csprojPath = Resolve-Path -Path $csprojPath
@@ -181,26 +182,29 @@ jobs:
$node.FileVersion = $match
$node.AssemblyVersion = $match
$csproj.Save($csprojPath)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish WPF GUI
continue-on-error: true
- name: Build
run: |
dotnet publish src/MaaWpfGui/MaaWpfGui.csproj -c Release -o install
$env:GITHUB_WORKFLOW = 'dev-build-win' # pretend this is a dev-build-win workflow
$env:GITHUB_EVENT_PATH = "$pwd\\event.json"
$env:GITHUB_REF = "refs/heads/not_master"
$env:MAA_BUILDER_MAA_VERSION = '${{ needs.meta.outputs.tag }}'
./build.cmd DevBuild
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Organize Install Files
- name: Cleanup checksum file
run: |
rm -vf ./artifacts/checksum.json
shell: bash
run: |
rm -rf install/*.pdb
rm -rf install/msvc-debug
rm -rf install/*.h
cp tools/DependencySetup_依赖库安装.bat install
- name: Upload MAA to Github
uses: actions/upload-artifact@v4
with:
name: MAA-win-${{ matrix.arch }}
path: install
name: MAA-win-${{ matrix.lowercase_target }}
path: artifacts
ubuntu:
# Prevent duplicate runs on organization branches with PRs
@@ -209,14 +213,15 @@ jobs:
github.event.pull_request.base.repo.full_name
needs: meta
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
matrix:
arch: [aarch64, x86_64]
fail-fast: false
permissions:
actions: write
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
@@ -225,48 +230,40 @@ jobs:
git submodule update --init --depth 1 3rdparty/EmulatorExtras
git submodule update --init --depth 1 src/maa-cli
- name: Cache MaaDeps and Toolchain
id: cache-maadeps
uses: actions/cache@v4
with:
path: ./MaaDeps
key: ${{ runner.os }}-${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-maadeps-${{ hashFiles('tools/maadeps-download.py', 'tools/linux-toolchain-download.py') }}
- name: Install cross compile toolchains
if: ${{ matrix.arch != 'x86_64' }}
run: |
sudo apt-get update
sudo apt-get install g++-12-aarch64-linux-gnu g++-12-aarch64-linux-gnu
- name: Bootstrap MaaDeps and Toolchain
if: steps.cache-maadeps.outputs.cache-hit != 'true'
# Caching not necessary on ubuntu runner
- name: Bootstrap MaaDeps
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 tools/maadeps-download.py ${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-linux
python3 tools/linux-toolchain-download.py ${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}
python3 maadeps-download.py ${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-linux
- name: Install llvm 20
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20
- name: Config cmake
- name: Build MAA
run: |
mkdir -p build
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_COMPILE_WARNING_AS_ERROR=ON \
-DMAADEPS_TRIPLET='maa-${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-linux' \
-DINSTALL_THIRD_LIBS=ON \
-DINSTALL_RESOURCE=ON \
-DINSTALL_PYTHON=ON \
-DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}' \
-DCMAKE_TOOLCHAIN_FILE=cmake/linux/maa-${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-linux-toolchain.cmake
-DMAA_VERSION='${{ needs.meta.outputs.tag }}'
cmake --build build --parallel $(nproc --all)
- name: Build
run: |
cmake --build build --config Release --parallel $(nproc)
env:
CLICOLOR_FORCE: 1
- name: Install
run: |
mkdir -p install
cmake --install build --prefix install --config Release
cmake --install build --prefix install
env:
CC: ${{ matrix.arch == 'x86_64' && 'gcc-12' || 'aarch64-linux-gnu-gcc-12' }}
CXX: ${{ matrix.arch == 'x86_64' && 'g++-12' || 'aarch64-linux-gnu-g++-12' }}
CMAKE_COLOR_DIAGNOSTICS: ON
CLICOLOR_FORCE: 1
CXXFLAGS: | # workaround for gcc bugs
-Wno-error=restrict -Wno-error=array-bounds -Wno-error=stringop-overread -Wno-error=missing-field-initializers
- name: Setup Cross Compile Toolchains for CLI
uses: ./src/maa-cli/.github/actions/setup
@@ -311,7 +308,7 @@ jobs:
ln -sv usr/share/maa/maa Maa.AppDir/AppRun
mkdir -pv Maa.AppDir/usr/share/metainfo/
cp -v tools/AppImage/io.github.maaassistantarknights.maaassistantarknights.metainfo.xml Maa.AppDir/usr/share/metainfo/
wget "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
# appimagetool with embedded runtime does not support cross build, till AppImage/appimagetool 7a10b8
wget "https://github.com/AppImage/type2-runtime/releases/download/old/runtime-fuse3-${{ matrix.arch }}"
chmod a+x appimagetool-x86_64.AppImage
@@ -340,44 +337,36 @@ jobs:
github.event.pull_request.base.repo.full_name
needs: meta
runs-on: macos-latest
runs-on: macos-14
strategy:
matrix:
arch: [arm64, x86_64]
fail-fast: false
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
# ninja 1.13.1 is already installed and up-to-date. To reinstall 1.13.1, run: brew reinstall ninja
# - name: Install Dependencies
# run: |
# brew install ninja
- name: Install Dependencies
run: |
brew install ninja
# Caching not necessary on macOS runner
- name: Bootstrap MaaDeps
run: |
[[ ${{ matrix.arch }} = "arm64" ]] && triplet="arm64-osx" || triplet="x64-osx"
python3 tools/maadeps-download.py ${triplet}
python3 maadeps-download.py ${triplet}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Config cmake
- name: Configure MaaCore
run: |
cmake -B build -GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURES='${{ matrix.arch }}' \
-DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}'
cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES='${{ matrix.arch }}' -DMAA_VERSION='${{ needs.meta.outputs.tag }}'
- name: Build
- name: Build MaaCore
run: |
cmake --build build --config Release --parallel $(nproc)
- name: Install
run: |
cmake --install build --prefix install --config Release
cmake --build build
cmake --install build --prefix install
- name: Upload MAA to Github
uses: actions/upload-artifact@v4
@@ -392,10 +381,10 @@ jobs:
github.event.pull_request.base.repo.full_name
needs: [meta, macOS-Core]
runs-on: macos-latest
runs-on: macos-14
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
@@ -410,13 +399,13 @@ jobs:
git submodule update --init --depth 1 src/MaaMacGui
- name: Download Arm64 MAA from Github
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: MAACore-macos-arm64
path: install-arm64
- name: Download x64 MAA from Github
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: MAACore-macos-x86_64
path: install-x86_64
@@ -558,7 +547,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download MAA from Github
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
path: assets
@@ -571,7 +560,7 @@ jobs:
find . -type f | while read f; do mv -fvt . $f; done
- name: Release to Github
uses: softprops/action-gh-release@v2.3.3
uses: softprops/action-gh-release@v2
with:
body_path: CHANGELOG.md
files: |

View File

@@ -1,57 +0,0 @@
name: "CodeQL MaaCore and MaaWpfGui Analysis"
on:
pull_request:
branches: ["dev"]
paths:
- "3rdparty/include/**"
- "include/**"
- "src/**"
- "cmake/**"
- "CMakeLists.txt"
- ".github/workflows/codeql-core.yml"
- "!**/*.md"
- "!**/*.xaml"
schedule:
- cron: "45 11 * * *" # Runs daily at 11:45 UTC
workflow_dispatch:
permissions:
actions: write
contents: read
packages: read
security-events: write
jobs:
analyze-manual:
name: Analyze MaaCore and MaaWpfGui
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
show-progress: false
- name: Setup CodeQL
uses: github/codeql-action/init@v3
with:
languages: c-cpp,csharp
build-mode: manual
- name: Run CodeQL
uses: github/codeql-action/analyze@v3
with:
category: "/language:multi-manual"
- name: Delete old caches
shell: pwsh
run: |
$oldCaches = gh cache list --key codeql --order asc --json key | ConvertFrom-Json | Select-Object -SkipLast 1
foreach ($cache in $oldCaches) {
if ($cache.key) {
Write-Host "Deleting cache: $($cache.key)"
gh cache delete $cache.key
}
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,50 +0,0 @@
name: "CodeQL Website Analysis"
on:
pull_request:
branches: ["dev"]
paths:
- "website/**"
- "!**/*.md"
schedule:
- cron: "10 12 * * *" # Runs daily at 12:10 UTC
workflow_dispatch:
permissions:
actions: write
contents: read
security-events: write
jobs:
analyze-website:
name: Analyze Website (JavaScript/TypeScript)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
show-progress: false
- name: Setup CodeQL for JavaScript/TypeScript
uses: github/codeql-action/init@v3
with:
languages: javascript-typescript
build-mode: none
- name: Run CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:multi-none"
- name: Delete old caches
shell: bash
run: |
oldCaches=$(gh cache list --key codeql --order asc --json key | jq -r '.[] | .key' | head -n -1)
for cache in $oldCaches; do
if [ -n "$cache" ]; then
echo "Deleting cache: $cache"
gh cache delete "$cache" --confirm
fi
done
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,36 +0,0 @@
name: "CodeQL Workflows Analysis"
on:
pull_request:
branches: ["dev"]
paths:
- ".github/**/*.yml"
schedule:
- cron: "00 12 * * *" # Runs daily at 12:00 UTC
workflow_dispatch:
permissions:
actions: write
contents: read
security-events: write
jobs:
analyze-workflows:
name: Analyze GitHub Workflows
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
show-progress: false
- name: Setup CodeQL for GitHub Actions
uses: github/codeql-action/init@v3
with:
languages: actions
build-mode: none
- name: Run CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:multi-none"

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
fetch-depth: 0
show-progress: false
@@ -48,7 +48,7 @@ jobs:
echo '======='
echo 'Target PR: ${{ github.event.pull_request.html_url }}' >> $PR_BODY
echo 'Target RP: ${{ github.event.pull_request.html_url }}' >> $PR_BODY
echo '' >> $PR_BODY
echo '<details><summary>Debug info</summary>' >> $PR_BODY
echo '' >> $PR_BODY

View File

@@ -1,152 +0,0 @@
name: Auto Close not reading issues or Fold checkboxes
on:
issues:
types: [opened]
jobs:
check-then-close-or-fold:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Check for duplicate issues in last hour
id: duplicate-check
uses: actions/github-script@v8
with:
script: |
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
const currentIssueCreatedAt = new Date(context.payload.issue.created_at);
const issueAuthor = context.payload.issue.user.login;
// 重新获取该用户最近的 issues
const { data: userIssues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
creator: issueAuthor,
state: 'all',
since: oneHourAgo.toISOString(),
per_page: 30
});
// 过滤出1小时内创建的其他 issues排除当前 issue
const recentIssues = userIssues.filter(issue => {
const issueCreatedAt = new Date(issue.created_at);
return issue.number !== context.issue.number &&
issueCreatedAt >= oneHourAgo &&
issueCreatedAt < currentIssueCreatedAt;
});
if (recentIssues.length > 0) {
// 给当前 issue 添加标签
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['rapid-submission']
});
// 给1小时内的其他 issues 也添加标签
for (const issue of recentIssues) {
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: ['rapid-submission']
});
console.log(`Added rapid-submission label to issue #${issue.number}`);
} catch (error) {
console.log(`Failed to add label to issue #${issue.number}: ${error.message}`);
}
}
}
- name: Check checkbox status
id: unread-checkbox-check
uses: actions/github-script@v8
with:
script: |
// 找不到###就算了
if (!/###([^#]+)###/.test(context.payload.issue.body)) {
return false;
}
var checkList = /###([^#]+)###/.exec(context.payload.issue.body)[1];
const UnreadRegexCn = /- \[x\]\s*.*?我.*未仔细阅读/i;
const UnreadRegexCn_ = /- \[ \]\s*.*?我.*未仔细阅读/i;
if (/- \[(x| )\]\s*.*?[\u4e00-\u9fa5]+/i.test(checkList)) { // 中英区分
if (UnreadRegexCn.test(checkList)) {
return true;
}
checkList = checkList.replace(UnreadRegexCn_, "");
return /- \[ \]\s*.*?[\u4e00-\u9fa5]+/i.test(checkList);
}
const texts = [
'I have checked all the options without carefully reading the content and believe this will not affect issue resolution.'];
return texts.some(text => new RegExp(`- \\[x\\]\\s*${text}`).test(context.payload.issue.body));
- name: Close and lock issue
if: steps.unread-checkbox-check.outputs.result == 'true'
uses: actions/github-script@v8
with:
script: |
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
state: 'closed',
state_reason: 'not_planned'
});
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['low-quality-report']
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: '因为未阅读模板提示并正确提交,触发了自动关闭规则\n\nBecause the template prompt was not read and submitted correctly, the automatic closing rule was triggered'
});
- name: Fold checkboxes
if: steps.unread-checkbox-check.outputs.result == 'false'
uses: actions/github-script@v8
with:
script: |
const originalBody = context.payload.issue.body;
if (originalBody.includes('<details><summary>Checkboxes</summary>\n\n')) {
return;
}
const checkboxSectionRegex_cn_bug = /([\s\S]*?)(### 问题描述\n\n)/;
const checkboxSectionRegex_cn_feat = /([\s\S]*?)(### 说说你遇到的问题?\n\n)/;
const checkboxSectionRegex_en_bug = /([\s\S]*?)(### Description\n\n)/;
const checkboxSectionRegex_en_feat = /([\s\S]*?)(### The problems you have encountered?\n\n)/;
const foldedBody_cn_bug = originalBody.replace(
checkboxSectionRegex_cn_bug,
`<details><summary>Checkboxes</summary>\n\n$1\n\n</details>\n\n$2`
);
const foldedBody_cn_feat = foldedBody_cn_bug.replace(
checkboxSectionRegex_cn_feat,
`<details><summary>Checkboxes</summary>\n\n$1\n\n</details>\n\n$2`
);
const foldedBody_en_bug = foldedBody_cn_feat.replace(
checkboxSectionRegex_en_bug,
`<details><summary>Checkboxes</summary>\n\n$1\n\n</details>\n\n$2`
);
const foldedBody = foldedBody_en_bug.replace(
checkboxSectionRegex_en_feat,
`<details><summary>Checkboxes</summary>\n\n$1\n\n</details>\n\n$2`
);
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: foldedBody
});

View File

@@ -31,7 +31,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Check out code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false

View File

@@ -44,14 +44,14 @@ jobs:
- name: Checkout repository
if: steps.check_push.outputs.is_pr != 'True'
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
persist-credentials: false
- name: Setup python
if: steps.check_push.outputs.is_pr != 'True'
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: "3.11"
@@ -102,7 +102,7 @@ jobs:
fi
- name: Push changes
if: steps.check_push.outputs.is_pr != 'True' && steps.commit_changes.outputs.have_commits == 'True' && github.repository_owner == 'MaaAssistantArknights'
if: steps.check_push.outputs.is_pr != 'True' && steps.commit_changes.outputs.have_commits == 'True'
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.MAA_RESOURCE_SYNC }}

View File

@@ -9,7 +9,6 @@ on:
workflow_dispatch:
inputs:
tag:
description: "Name of the tag to create for the release"
type: string
required: true
@@ -20,7 +19,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.MAARELEASE_RELEASE }}

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cleanup Previous Comment
uses: actions/github-script@v8
uses: actions/github-script@v7
with:
script: |
const { data: comments } = await github.rest.issues.listComments({
@@ -28,7 +28,7 @@ jobs:
});
}
- name: Check Commits
uses: actions/github-script@v8
uses: actions/github-script@v7
with:
script: |
const { data: commits } = await github.rest.pulls.listCommits({

View File

@@ -30,15 +30,17 @@ jobs:
runs-on: windows-latest
strategy:
matrix:
arch: [x64]
msbuild_target: [x64]
fail-fast: false
env:
MAABUILDER_TARGET_PLATFORM: ${{ matrix.msbuild_target }}
outputs:
tag: ${{ steps.set_tag.outputs.tag }}
pre_version: ${{ steps.set_tag.outputs.pre_version }}
main_tag_name: ${{ steps.push_main_tag.outputs.main_tag_name }}
changelog: ${{ steps.read_changelog.outputs.content }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
# repository: 'MaaAssistantArknights/MaaAssistantArknights'
#ref: ${{ inputs.ref }}
@@ -166,35 +168,6 @@ jobs:
with:
path: ./changelog_notag.md
- name: Cache MaaDeps
id: cache-maadeps
uses: actions/cache@v4
with:
path: |
./MaaDeps
key: ${{ runner.os }}-${{ matrix.arch }}-maadeps-${{ hashFiles('./tools/maadeps-download.py') }}
- name: Bootstrap MaaDeps
if: steps.cache-maadeps.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 tools/maadeps-download.py ${{ matrix.arch }}-windows
- name: Config cmake
run: |
mkdir -p build
cmake -B build ${{ matrix.arch == 'arm64' && '-A ARM64' }} -DCMAKE_BUILD_TYPE=Release -DMAADEPS_TRIPLET='maa-${{ matrix.arch }}-windows' -DINSTALL_RESOURCE=ON -DINSTALL_PYTHON=ON -DMAA_HASH_VERSION='${{ steps.set_tag.outputs.tag }}' -DBUILD_WPF_GUI=OFF
- name: Build
run: |
cmake --build build --config Release --parallel $env:NUMBER_OF_PROCESSORS
- name: Install
run: |
mkdir -p install
cmake --install build --prefix install --config Release
- name: Cache .nuke/temp, ~/.nuget/packages
id: cache-nuget
uses: actions/cache@v4
@@ -202,13 +175,28 @@ jobs:
path: |
.nuke/temp
~/.nuget/packages
key: ${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('**/*.csproj') }}
key: ${{ runner.os }}-${{ matrix.msbuild_target }}-${{ hashFiles('**/global.json', '**/*.csproj') }}
- name: Restore dependencies
if: steps.cache-nuget.outputs.cache-hit != 'true'
run: dotnet restore src/MaaWpfGui/MaaWpfGui.csproj
run: dotnet restore
- name: Taggify Version for csproj
- name: Cache MaaDeps
id: cache-maadeps
uses: actions/cache@v4
with:
path: |
./MaaDeps
key: ${{ runner.os }}-${{ matrix.msbuild_target }}-maadeps-${{ hashFiles('./maadeps-download.py') }}
- name: Bootstrap MaaDeps
if: steps.cache-maadeps.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 maadeps-download.py ${{ matrix.msbuild_target }}-windows
- name: Taggify Version
run: |
$csprojPath = "src/MaaWpfGui/MaaWpfGui.csproj"
$csprojPath = Resolve-Path -Path $csprojPath
@@ -218,6 +206,8 @@ jobs:
} else {
$match = "0.0.1"
}
echo "Tag value: $tag"
echo "Version value: $match"
[xml]$csproj = Get-Content -Path $csprojPath
$node = $csproj.Project.PropertyGroup | where {$_.ApplicationVersion -ne $null}
$node.InformationalVersion = $tag
@@ -225,25 +215,25 @@ jobs:
$node.FileVersion = $match
$node.AssemblyVersion = $match
$csproj.Save($csprojPath)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish WPF GUI
- name: Run './build.cmd DevBuild'
run: |
dotnet publish src/MaaWpfGui/MaaWpfGui.csproj -c Release -o install
$env:GITHUB_WORKFLOW = 'dev-build-win' # pretend this is a dev-build-win workflow
$env:MAA_BUILDER_MAA_VERSION = "${{ steps.set_tag.outputs.tag }}"
echo "tag: " $env:MAA_BUILDER_MAA_VERSION
- name: Organize Install Files
shell: bash
run: |
rm -rf install/*.pdb
rm -rf install/msvc-debug
rm -rf install/*.h
cp tools/DependencySetup_依赖库安装.bat install
./build.cmd DevBuild
env:
Reason: "Build nightly version"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload MAA to Github
uses: actions/upload-artifact@v4
with:
name: MAA-win-${{ matrix.arch }}
path: install
name: MAA-win-${{ matrix.msbuild_target }}
path: artifacts
- name: Push tag to main repo
id: push_main_tag
@@ -262,7 +252,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Fetch MaaRelease
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
repository: ${{ format('{0}/{1}', github.repository_owner, 'MaaRelease') }}
fetch-depth: 0
@@ -292,14 +282,14 @@ jobs:
echo ${{ needs.build-win-nightly.outputs.tag }}
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
path: MaaAssistantArknights
token: ${{ secrets.MAARELEASE_RELEASE }}
show-progress: false
- name: Download MAA from Github
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: MAA-win-${{ matrix.target }}
path: ${{ format('{0}/{1}', 'build-ota', needs.build-win-nightly.outputs.tag) }}
@@ -338,7 +328,8 @@ jobs:
cd build-ota
pushd ${{ needs.build-win-nightly.outputs.tag }}
zip -r MAA-${{ env.release_tag }}-win-${{ matrix.target }}.zip ./*
zip -d *.zip '*.lib' '*.pdb' '*.exp' '*.config' '*.xml'
mv *.zip MAA-${{ env.release_tag }}-win-${{ matrix.target }}.zip
popd
$GITHUB_WORKSPACE/MaaAssistantArknights/tools/OTAPacker/build.sh 'MaaAssistantArknights/MaaAssistantArknights' ./config ${{ matrix.target }} "${{ github.repository_owner }}/MaaRelease"

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Fetch MaaRelease
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
repository: ${{ format('{0}/{1}', github.repository_owner, 'MaaRelease') }}
@@ -94,10 +94,10 @@ jobs:
- x64
steps:
- name: Download release config
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
- name: Fetch MaaRelease
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
repository: ${{ format('{0}/{1}', github.repository_owner, 'MaaRelease') }}
@@ -106,7 +106,7 @@ jobs:
token: ${{ secrets.MAARELEASE_RELEASE }}
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
path: MaaAssistantArknights

View File

@@ -1,4 +1,4 @@
name: Resource Updater
name: res-update-game
on:
schedule:
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone ArknightsGameResource for Official
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
repository: yuanyan3060/ArknightsGameResource
@@ -47,7 +47,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone ArknightsGameResource_Yostar for Overseas
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
repository: ArknightsAssets/ArknightsGamedata
@@ -89,7 +89,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone arknights-toolbox-update for Taiwan
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
repository: arkntools/arknights-toolbox-update
@@ -125,14 +125,14 @@ jobs:
compression-level: 0
update-game-resources:
# Remove the comment in case of rate limitations on the runners/instances.
# In case of rate limitations on the runners/instances, add dependency, by removing the comment
# needs: [clone-resources-official, clone-resources-overseas, clone-resources-txwy]
if: github.repository_owner == 'MaaAssistantArknights'
runs-on: ubuntu-latest
runs-on: windows-latest
steps:
- name: Checkout MAA
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
# TL;DR https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/9872#issuecomment-2251378371
# actions/checkout uses ${{ secrets.GITHUB_TOKEN }} by default, meaning all steps will inherit it
@@ -140,125 +140,118 @@ jobs:
show-progress: false
fetch-depth: 3
- name: Restore ResourceUpdater from cache
id: resupd-cache
- name: Restore ResourceUpdater.exe from cache
id: cache-resupd
uses: actions/cache/restore@v4
with:
key: ResourceUpdater-${{ runner.os }}-${{ hashFiles('tools/ResourceUpdater/main.cpp') }}
key: Resource-updater-${{ hashFiles('./tools/ResourceUpdater/main.cpp') }}
path: |
./tools/ResourceUpdater/libc++.so.1
./tools/ResourceUpdater/libc++abi.so.1
./tools/ResourceUpdater/libopencv_world4.so.411
./tools/ResourceUpdater/libunwind.so.1
./tools/ResourceUpdater/ResourceUpdater
./tools/ResourceUpdater/x64/Release/opencv_world4_maa.dll
./tools/ResourceUpdater/x64/Release/ResourceUpdater.exe
- name: Cache MaaDeps
if: steps.resupd-cache.outputs.cache-hit != 'true'
id: maadeps-cache
if: steps.cache-resupd.outputs.cache-hit != 'true'
id: cache-maadeps
uses: actions/cache@v4
with:
path: |
./MaaDeps
key: ${{ runner.os }}-x64-maadeps-${{ hashFiles('tools/maadeps-download.py', 'tools/linux-toolchain-download.py') }}
key: ${{ runner.os }}-x64-maadeps-${{ hashFiles('./maadeps-download.py') }}
- name: Bootstrap MaaDeps
if: steps.resupd-cache.outputs.cache-hit != 'true' && steps.maadeps-cache.outputs.cache-hit != 'true'
if: steps.cache-resupd.outputs.cache-hit != 'true' && steps.cache-maadeps.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 tools/maadeps-download.py x64-linux
python3 tools/linux-toolchain-download.py x64
python3 maadeps-download.py x64-windows
- name: Install llvm-20
if: steps.resupd-cache.outputs.cache-hit != 'true'
- name: Add msbuild to PATH
if: steps.cache-resupd.outputs.cache-hit != 'true'
uses: microsoft/setup-msbuild@v2
- name: Build Resource Updater
if: steps.cache-resupd.outputs.cache-hit != 'true'
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20
MSBUILD tools/ResourceUpdater/ResourceUpdater.vcxproj /t:rebuild /p:Configuration="Release" /p:Platform="x64" /p:BuildProjectReferences=false /m
- name: Config cmake
if: steps.resupd-cache.outputs.cache-hit != 'true'
run: |
mkdir -p build
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DMAADEPS_TRIPLET='maa-x64-linux' \
-DBUILD_RES_UPDATER=ON \
-DCMAKE_TOOLCHAIN_FILE=cmake/linux/maa-x64-linux-toolchain.cmake
- name: Build
if: steps.resupd-cache.outputs.cache-hit != 'true'
run: |
cmake --build build --config Release --parallel $(nproc)
- name: Install
if: steps.resupd-cache.outputs.cache-hit != 'true'
run: |
cmake --install build --config Release --prefix tools/ResourceUpdater
- name: Save ResourceUpdater to cache
if: always() && steps.resupd-cache.outputs.cache-hit != 'true'
- name: Save ResourceUpdater.exe to cache
if: always() && steps.cache-resupd.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
key: ResourceUpdater-${{ runner.os }}-${{ hashFiles('tools/ResourceUpdater/main.cpp') }}
key: Resource-updater-${{ hashFiles('./tools/ResourceUpdater/main.cpp') }}
path: |
./tools/ResourceUpdater/libc++.so.1
./tools/ResourceUpdater/libc++abi.so.1
./tools/ResourceUpdater/libopencv_world4.so.411
./tools/ResourceUpdater/libunwind.so.1
./tools/ResourceUpdater/ResourceUpdater
- name: Wait for TXWY resources
uses: lewagon/wait-on-check-action@v1.4.0
with:
ref: ${{ github.ref }}
check-name: 'clone-resources-txwy'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 5
./tools/ResourceUpdater/x64/Release/opencv_world4_maa.dll
./tools/ResourceUpdater/x64/Release/ResourceUpdater.exe
- name: Download txwy
uses: actions/download-artifact@v5
id: download-txwy
uses: actions/download-artifact@v4.1.8
continue-on-error: true
with:
name: txwy
path: ./tools/ResourceUpdater/Overseas/tw/gamedata/excel
path: ./tools/ResourceUpdater/x64/Release/Overseas/tw/gamedata/excel
- name: Wait for Overseas resources
uses: lewagon/wait-on-check-action@v1.4.0
- name: Delay txwy
if: steps.download-txwy.outcome == 'failure'
run: |
Start-Sleep -s 20
- name: Re-download txwy
if: steps.download-txwy.outcome == 'failure'
uses: actions/download-artifact@v4.1.8
with:
ref: ${{ github.ref }}
check-name: 'clone-resources-overseas'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 5
name: txwy
path: ./tools/ResourceUpdater/x64/Release/Overseas/tw/gamedata/excel
- name: Download Overseas
uses: actions/download-artifact@v5
id: download-overseas
uses: actions/download-artifact@v4.1.8
continue-on-error: true
with:
name: overseas
path: ./tools/ResourceUpdater/Overseas
path: ./tools/ResourceUpdater/x64/Release/Overseas
- name: Wait for Official resources
uses: lewagon/wait-on-check-action@v1.4.0
- name: Delay Overseas
if: steps.download-overseas.outcome == 'failure'
run: |
Start-Sleep -s 20
- name: Re-download Overseas
if: steps.download-overseas.outcome == 'failure'
uses: actions/download-artifact@v4.1.8
with:
ref: ${{ github.ref }}
check-name: 'clone-resources-official'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 5
name: overseas
path: ./tools/ResourceUpdater/x64/Release/Overseas
- name: Download Official
uses: actions/download-artifact@v5
id: download-official
uses: actions/download-artifact@v4.1.8
continue-on-error: true
with:
name: official
path: ./tools/ResourceUpdater/Official
path: ./tools/ResourceUpdater/x64/Release/Official
- name: Delay Official
if: steps.download-official.outcome == 'failure'
run: |
Start-Sleep -s 20
- name: Re-download Official
if: steps.download-official.outcome == 'failure'
uses: actions/download-artifact@v4.1.8
with:
name: official
path: ./tools/ResourceUpdater/x64/Release/Official
- name: Run Resource Updater
run: |
./tools/ResourceUpdater/ResourceUpdater
./tools/ResourceUpdater/x64/Release/ResourceUpdater.exe
- name: Task Sorting
id: task_sorting
run: |
python3 tools/TaskSorter/TaskSorter.py
echo "gitdiff=$(echo $(git diff --name-only --diff-filter=ACM 2>/dev/null | grep '\.json$'))" >> $GITHUB_OUTPUT
Write-Output "gitdiff=$(git diff --name-only --diff-filter=ACM 2>$null | Select-String -Pattern '\.json$' -List)" >> $env:GITHUB_OUTPUT
- name: Run prettier
uses: Nerixyz/actionsx-prettier@v3-adj
@@ -267,12 +260,11 @@ jobs:
- name: Update version.json date if necessary
id: update_version
run: |
tools/ResourceUpdater/version.sh
run: pwsh tools/ResourceUpdater/version.ps1
- name: Setup python
if: steps.update_version.outputs.contains_png == 'True'
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: "3.11"
@@ -308,19 +300,19 @@ jobs:
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add .
commit_msg="${{ github.event.inputs.commit_message }}"
if [ -z "$commit_msg" ]; then
commit_msg="chore: Auto Update Game Resources - $(date '+%Y-%m-%d')"
else
commit_msg=$(echo "$commit_msg" | xargs) # Trim whitespace
fi
$commit_msg = "${{ github.event.inputs.commit_message }}"
if ([string]::IsNullOrWhiteSpace($commit_msg)) {
$commit_msg = "chore: Auto Update Game Resources - $(Get-Date -Format 'yyyy-MM-dd')"
} else {
$commit_msg = $commit_msg.Trim()
}
run_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
$run_url = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
git commit -m "$commit_msg" -m "$run_url" -m "[skip changelog]"
if [ $? -eq 0 ]; then
echo "have_commits=True" >> $GITHUB_OUTPUT
fi
if ($LASTEXITCODE -eq 0) {
Write-Output "have_commits=True" >> $env:GITHUB_OUTPUT
}
git pull origin ${{ github.ref_name }} --rebase

View File

@@ -7,22 +7,20 @@ on:
- "include/**"
- "src/Cpp/**"
- "src/MaaCore/**"
- "src/SyncRes/**"
- "MAA.sln"
- "resource/**"
- "!**/*.md"
- "cmake/**"
- "CMakeLists.txt"
- "tools/maadeps-download.py"
pull_request:
paths:
- "3rdparty/include/**"
- "include/**"
- "src/Cpp/**"
- "src/MaaCore/**"
- "src/SyncRes/**"
- "MAA.sln"
- "resource/**"
- "!**/*.md"
- "cmake/**"
- "CMakeLists.txt"
- "tools/maadeps-download.py"
workflow_dispatch:
concurrency:
@@ -35,108 +33,89 @@ jobs:
if: github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name !=
github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
- name: Generate cache key
id: cache_key
run: |
echo "key=Smoke-testing-${{ hashFiles('src/Cpp/**', 'src/MaaCore/**', '3rdparty/include/**', 'include/**', 'cmake/**', 'CMakeLists.txt', 'tools/maadeps-download.py', 'tools/linux-toolchain-download.py') }}" >> $GITHUB_OUTPUT
Write-Output "key=Smoke-testing-${{ hashFiles('src/Cpp/**', 'src/MaaCore/**', 'src/SyncRes/**', '3rdparty/include/**', 'include/**', 'MAA.sln') }}" >> $env:GITHUB_OUTPUT
- name: Restore cache smoke-testing
id: smoke-cache
id: cache-exe
uses: actions/cache/restore@v4
with:
key: ${{ steps.cache_key.outputs.key }}
path: |
./install/AsstCaller.h
./install/AsstPort.h
./install/libc++.so.1
./install/libc++abi.so.1
./install/libfastdeploy_ppocr.so
./install/libMaaCore.so
./install/libonnxruntime.so.1
./install/libopencv_world4.so.411
./install/libunwind.so.1
./install/smoke_test
./x64/Debug/Sample.exe
./x64/Debug/fastdeploy_ppocr.dll
./x64/Debug/MaaCore.dll
./x64/Debug/onnxruntime_maa.dll
./x64/Debug/opencv_world4d_maa.dll
- name: Fetch submodules
if: steps.smoke-cache.outputs.cache-hit != 'true'
if: steps.cache-exe.outputs.cache-hit != 'true'
run: |
git submodule update --init --depth 1 3rdparty/EmulatorExtras
- name: Cache MaaDeps
if: steps.smoke-cache.outputs.cache-hit != 'true'
id: maadeps-cache
if: steps.cache-exe.outputs.cache-hit != 'true'
id: cache-maadeps
uses: actions/cache@v4
with:
path: ./MaaDeps
key: ${{ runner.os }}-x64-maadeps-${{ hashFiles('tools/maadeps-download.py', 'tools/linux-toolchain-download.py') }}
path: |
./MaaDeps
key: ${{ runner.os }}-x64-maadeps-${{ hashFiles('./maadeps-download.py') }}
- name: Bootstrap MaaDeps
if: steps.smoke-cache.outputs.cache-hit != 'true' && steps.maadeps-cache.outputs.cache-hit != 'true'
if: steps.cache-exe.outputs.cache-hit != 'true' && steps.cache-maadeps.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 tools/maadeps-download.py x64-linux
python3 tools/linux-toolchain-download.py x64
python3 maadeps-download.py x64-windows
- name: Install llvm-20
if: steps.smoke-cache.outputs.cache-hit != 'true'
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20
- name: Add msbuild to PATH
if: steps.cache-exe.outputs.cache-hit != 'true'
uses: microsoft/setup-msbuild@v2
with:
msbuild-architecture: x64
- name: Config cmake
if: steps.smoke-cache.outputs.cache-hit != 'true'
- name: Build MaaSample
if: steps.cache-exe.outputs.cache-hit != 'true'
run: |
mkdir -p build
cmake -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DMAADEPS_TRIPLET='maa-x64-linux' \
-DBUILD_SMOKE_TEST=ON \
-DCMAKE_TOOLCHAIN_FILE=cmake/linux/maa-x64-linux-toolchain.cmake
MSBUILD src/Cpp/MaaSample.slnf -t:restore,build -p:Configuration="Debug" -p:Platform="x64" -m
- name: Build
if: steps.smoke-cache.outputs.cache-hit != 'true'
- name: Copy resource to build directory
if: steps.cache-exe.outputs.cache-hit == 'true'
run: |
cmake --build build --config Debug --parallel $(nproc)
- name: Install
if: steps.smoke-cache.outputs.cache-hit != 'true'
run: |
mkdir -p install
cmake --install build --prefix install --config Debug
(robocopy "resource" "x64/Debug/resource" /E /XD "Arknights-Tile-Pos" /MT:4 > $null);
if ($LASTEXITCODE -lt 2) { $global:LASTEXITCODE = $null }
(robocopy "resource/Arknights-Tile-Pos" "x64/Debug/resource/Arknights-Tile-Pos" "overview.json" > $null);
if ($LASTEXITCODE -lt 2) { $global:LASTEXITCODE= $null }
- name: Run tests
run: |
./tools/SmokeTesting/run_tests.sh
pwsh tools/SmokeTesting/run_tests.ps1
- name: Save cache smoke-testing (only in dev)
if: steps.smoke-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/dev'
if: steps.cache-exe.outputs.cache-hit != 'true' && github.ref == 'refs/heads/dev'
uses: actions/cache/save@v4
with:
key: ${{ steps.cache_key.outputs.key }}
path: |
./install/AsstCaller.h
./install/AsstPort.h
./install/libc++.so.1
./install/libc++abi.so.1
./install/libfastdeploy_ppocr.so
./install/libMaaCore.so
./install/libonnxruntime.so.1
./install/libopencv_world4.so.411
./install/libunwind.so.1
./install/smoke_test
./x64/Debug/Sample.exe
./x64/Debug/fastdeploy_ppocr.dll
./x64/Debug/MaaCore.dll
./x64/Debug/onnxruntime_maa.dll
./x64/Debug/opencv_world4d_maa.dll
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: logs
path: ./install/debug
path: ./x64/Debug/debug

View File

@@ -21,7 +21,7 @@ jobs:
contents: none
steps:
- name: Close inactive issues
uses: actions/stale@v10
uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: ${{ env.daysBeforeStale }}

View File

@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout MaaAssistantArknights
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
@@ -27,7 +27,7 @@ jobs:
git show -s
- name: Checkout MaaResource
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
repository: MaaAssistantArknights/MaaResource
show-progress: false

View File

@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
show-progress: false
@@ -39,7 +39,7 @@ jobs:
run_install: false
- name: Setup Node.js environment
uses: actions/setup-node@v5
uses: actions/setup-node@v4
with:
node-version: 22
@@ -63,7 +63,7 @@ jobs:
if: github.event_name != 'pull_request'
steps:
- name: Download website artifacts
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
with:
name: dist
@@ -79,14 +79,6 @@ jobs:
- name: Show environment
run: echo ${{ env.AZURE_TARGET_ENV }}
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
if: env.AZURE_TARGET_ENV == 'prod'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: "."
publish_branch: gh-pages
- name: Deploy to Azure (prod)
id: deploy-prod
uses: Azure/static-web-apps-deploy@v1

7
.gitignore vendored
View File

@@ -467,10 +467,3 @@ Thumbs.db
# macOS Finder Shit
.DS_Store
# MaaSupportExtension config
/config/maa_pi_config.json
# build & install
build
install

127
.nuke/build.schema.json Normal file
View File

@@ -0,0 +1,127 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Build Schema",
"$ref": "#/definitions/build",
"definitions": {
"build": {
"type": "object",
"properties": {
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
},
"Help": {
"type": "boolean",
"description": "Shows the help text for this build assembly"
},
"Host": {
"type": "string",
"description": "Host for execution. Default is 'automatic'",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
},
"NoLogo": {
"type": "boolean",
"description": "Disables displaying the NUKE logo"
},
"Partition": {
"type": "string",
"description": "Partition to use on CI"
},
"Plan": {
"type": "boolean",
"description": "Shows the execution plan (HTML)"
},
"Profile": {
"type": "array",
"description": "Defines the profiles to load",
"items": {
"type": "string"
}
},
"Root": {
"type": "string",
"description": "Root directory during build execution"
},
"Skip": {
"type": "array",
"description": "List of targets to be skipped. Empty list skips all dependencies",
"items": {
"type": "string",
"enum": [
"Default",
"DevBuild",
"DevBuildDefault",
"DevBuildReleaseSimulation",
"ReleaseMaa",
"SetMaaChangeLog",
"SetPackageBundled",
"SetVersion",
"UseClean",
"UseCommitVersion",
"UseMaaChangeLog",
"UseMaaDevBundle",
"UseMaaRelease",
"UsePublishArtifact",
"UsePublishRelease",
"UseRsVersion",
"UseTagVersion",
"WithCompileCoreRelease",
"WithCompileWpfRelease",
"WithSyncRes"
]
}
},
"Target": {
"type": "array",
"description": "List of targets to be invoked. Default is '{default_target}'",
"items": {
"type": "string",
"enum": [
"Default",
"DevBuild",
"DevBuildDefault",
"DevBuildReleaseSimulation",
"ReleaseMaa",
"SetMaaChangeLog",
"SetPackageBundled",
"SetVersion",
"UseClean",
"UseCommitVersion",
"UseMaaChangeLog",
"UseMaaDevBundle",
"UseMaaRelease",
"UsePublishArtifact",
"UsePublishRelease",
"UseRsVersion",
"UseTagVersion",
"WithCompileCoreRelease",
"WithCompileWpfRelease",
"WithSyncRes"
]
}
},
"Verbosity": {
"type": "string",
"description": "Logging verbosity during build execution. Default is 'Normal'",
"enum": ["Minimal", "Normal", "Quiet", "Verbose"]
}
}
}
}
}

4
.nuke/parameters.json Normal file
View File

@@ -0,0 +1,4 @@
{
"$schema": "./build.schema.json",
"Solution": "tools/MaaBuilder.sln"
}

View File

@@ -6,11 +6,10 @@ src/maa-cli
src/MaaMacGui
website/
# docs/
docs/
resource/Arknights-Tile-Pos/
tools/OptimizeTemplates/optimize_templates.json
CITATION.cff
CHANGELOG.md
## FUCK FUCK

View File

@@ -12,12 +12,6 @@
"parser": "yaml",
"tabWidth": 2
}
},
{
"files": ["**/*.md"],
"options": {
"tabWidth": 2
}
}
]
}

View File

@@ -2,8 +2,7 @@
"json.schemas": [
{
"fileMatch": [
"resource/tasks/**/*.json",
"resource/global/**/resource/tasks/**/*.json",
"resource/tasks.json"
],
"url": "./docs/maa_tasks_schema.json"
}
@@ -12,8 +11,5 @@
"MaaDeps/vcpkg/buildtrees": true,
"MaaDeps/vcpkg/packages": true
},
"files.associations": {
"**/resource/tasks/**/*.json": "jsonc"
},
"C_Cpp.exclusionPolicy": "checkFilesAndFolders"
}

View File

@@ -7,7 +7,6 @@
#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
#include "exception.hpp"
@@ -41,49 +40,50 @@ public:
// explicit basic_array(basic_value<string_t>&& val);
template <
typename jsonization_t,
typename collection_t,
std::enable_if_t<
_utils::has_to_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
_utils::is_collection<collection_t>
&& std::is_constructible_v<value_type, _utils::range_value_t<collection_t>>,
bool> = true>
basic_array(const jsonization_t& value)
: basic_array(ext::jsonization<string_t, jsonization_t>().to_json(value))
basic_array(collection_t arr)
: _array_data(std::make_move_iterator(arr.begin()), std::make_move_iterator(arr.end()))
{
}
template <
typename fixed_array_t,
std::enable_if_t<_utils::is_fixed_array<fixed_array_t>, bool> = true>
basic_array(const fixed_array_t& arr)
: _array_data(arr.begin(), arr.end())
{
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
std::enable_if_t<_utils::has_to_json_in_member<jsonization_t>::value, bool> = true>
basic_array(const jsonization_t& value)
: basic_array(ext::jsonization<string_t, jsonization_t>().to_json_array(value))
: basic_array(value.to_json())
{
}
template <
typename jsonization_t,
std::enable_if_t<
std::is_rvalue_reference_v<jsonization_t&&>
&& _utils::has_move_to_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_move_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
basic_array(jsonization_t&& value)
: basic_array(ext::jsonization<string_t, jsonization_t>().move_to_json(std::move(value)))
std::enable_if_t<_utils::has_to_json_in_templ_spec<jsonization_t>::value, bool> = true>
basic_array(const jsonization_t& value)
: basic_array(ext::jsonization<jsonization_t>().to_json(value))
{
}
//template <
// typename jsonization_t,
// std::enable_if_t<
// std::is_rvalue_reference_v<jsonization_t&&>
// && _utils::has_move_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
// bool> = true>
//basic_array(jsonization_t&& value)
// : basic_array(
// ext::jsonization<string_t, jsonization_t>().move_to_json_array(std::move(value)))
//{
//}
template <typename... elem_ts>
basic_array(const std::tuple<elem_ts...>& tup)
{
foreach_tuple(tup, std::make_index_sequence<std::tuple_size_v<std::tuple<elem_ts...>>>());
}
template <typename first_t, typename second_t>
basic_array(std::pair<first_t, second_t> pair)
: _array_data({ std::move(pair.first), std::move(pair.second) })
{
}
~basic_array() noexcept = default;
@@ -120,30 +120,6 @@ public:
template <typename first_t, typename second_t>
std::pair<first_t, second_t> as_pair() const;
template <
typename value_t,
std::enable_if_t<
_utils::has_from_json_array_in_templ_spec<value_t, string_t>::value,
bool> = true>
value_t as() const&
{
value_t res;
ext::jsonization<string_t, value_t>().from_json_array(*this, res);
return res;
}
template <
typename value_t,
std::enable_if_t<
_utils::has_move_from_json_array_in_templ_spec<value_t, string_t>::value,
bool> = true>
value_t as() &&
{
value_t res;
ext::jsonization<string_t, value_t>().move_from_json_array(std::move(*this), res);
return res;
}
// Usage: get(key_1, key_2, ..., default_value);
template <typename... key_then_default_value_t>
auto get(key_then_default_value_t&&... keys_then_default_value) const;
@@ -216,19 +192,29 @@ public:
std::enable_if_t<_utils::is_fixed_array<fixed_array_t<value_t, Size>>, bool> = true>
explicit operator fixed_array_t<value_t, Size>() const
{
return as<fixed_array_t<value_t, Size>>();
return as_fixed_array<value_t, Size, fixed_array_t>();
}
template <typename... elem_ts>
explicit operator std::tuple<elem_ts...>() const
{
return as_tuple<elem_ts...>();
}
template <typename elem1_t, typename elem2_t>
explicit operator std::pair<elem1_t, elem2_t>() const
{
return as_pair<elem1_t, elem2_t>();
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() const&
std::enable_if_t<_utils::has_from_json_in_member<jsonization_t, string_t>::value, bool> =
true>
explicit operator jsonization_t() const
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json(*this, dst)) {
if (!dst.from_json(*this)) {
throw exception("Wrong JSON");
}
return dst;
@@ -237,43 +223,12 @@ public:
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() const&
explicit operator jsonization_t() const
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json_array(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_move_from_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_move_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() &&
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json(std::move(*this), dst)) {
throw exception("Wrong JSON");
}
return dst;
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_move_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() &&
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().move_from_json_array(
std::move(*this),
dst)) {
if (!ext::jsonization<jsonization_t>().from_json(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
@@ -289,6 +244,17 @@ private:
template <typename value_t>
auto get_helper(const value_t& default_value, size_t pos) const;
template <typename tuple_t>
tuple_t as_tuple_templ() const;
template <size_t index, typename tuple_t>
void set_tuple(tuple_t& tup) const;
template <typename Tuple, std::size_t... Is>
void foreach_tuple(const Tuple& t, std::index_sequence<Is...>)
{
(_array_data.emplace_back(std::get<Is>(t)), ...);
}
string_t format(size_t indent, size_t indent_times) const;
private:
@@ -402,32 +368,95 @@ inline bool basic_array<string_t>::all() const
return true;
}
namespace _as_collection_helper
{
template <typename T>
class has_emplace_back
{
template <typename U>
static auto test(int) -> decltype(std::declval<U>().emplace_back(), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
}
template <typename string_t>
template <typename value_t, template <typename...> typename collection_t>
inline collection_t<value_t> basic_array<string_t>::as_collection() const
{
return as<collection_t<value_t>>();
collection_t<value_t> result;
if constexpr (_as_collection_helper::has_emplace_back<collection_t<value_t>>::value) {
for (const auto& elem : _array_data) {
result.emplace_back(elem.template as<value_t>());
}
}
else {
for (const auto& elem : _array_data) {
result.emplace(elem.template as<value_t>());
}
}
return result;
}
template <typename string_t>
template <typename value_t, size_t Size, template <typename, size_t> typename fixed_array_t>
inline fixed_array_t<value_t, Size> basic_array<string_t>::as_fixed_array() const
{
return as<fixed_array_t<value_t, Size>>();
if (size() != Size) {
throw exception("Wrong array size");
}
fixed_array_t<value_t, Size> result;
for (size_t i = 0; i < Size; ++i) {
result.at(i) = _array_data.at(i).template as<value_t>();
}
return result;
}
template <typename string_t>
template <size_t index, typename tuple_t>
inline void basic_array<string_t>::set_tuple(tuple_t& tup) const
{
using elem_t = std::tuple_element_t<index, tuple_t>;
if constexpr (index > 0) {
set_tuple<index - 1>(tup);
}
std::get<index>(tup) = static_cast<elem_t>(at(index));
}
template <typename string_t>
template <typename tuple_t>
inline tuple_t basic_array<string_t>::as_tuple_templ() const
{
constexpr size_t tuple_size = std::tuple_size_v<tuple_t>;
if (size() != tuple_size) {
throw exception("Wrong array size");
}
tuple_t result;
set_tuple<tuple_size - 1>(result);
return result;
}
template <typename string_t>
template <typename... elem_ts>
inline std::tuple<elem_ts...> basic_array<string_t>::as_tuple() const
{
return as<std::tuple<elem_ts...>>();
return as_tuple_templ<std::tuple<elem_ts...>>();
}
template <typename string_t>
template <typename first_t, typename second_t>
inline std::pair<first_t, second_t> basic_array<string_t>::as_pair() const
{
return as<std::pair<first_t, second_t>>();
return as_tuple_templ<std::pair<first_t, second_t>>();
}
template <typename string_t>

View File

@@ -39,50 +39,32 @@ public:
// explicit basic_object(basic_value<string_t>&& val);
template <
typename jsonization_t,
typename map_t,
std::enable_if_t<
_utils::has_to_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
_utils::is_map<map_t>
&& std::is_constructible_v<value_type, _utils::range_value_t<map_t>>,
bool> = true>
basic_object(const jsonization_t& value)
: basic_object(ext::jsonization<string_t, jsonization_t>().to_json(value))
basic_object(map_t map)
: _object_data(std::make_move_iterator(map.begin()), std::make_move_iterator(map.end()))
{
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
std::enable_if_t<_utils::has_to_json_in_member<jsonization_t>::value, bool> = true>
basic_object(const jsonization_t& value)
: basic_object(ext::jsonization<string_t, jsonization_t>().to_json_object(value))
: basic_object(value.to_json())
{
}
template <
typename jsonization_t,
std::enable_if_t<
std::is_rvalue_reference_v<jsonization_t&&>
&& _utils::has_move_to_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_move_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
basic_object(jsonization_t&& value)
: basic_object(ext::jsonization<string_t, jsonization_t>().move_to_json(std::move(value)))
std::enable_if_t<_utils::has_to_json_in_templ_spec<jsonization_t>::value, bool> = true>
basic_object(const jsonization_t& value)
: basic_object(ext::jsonization<jsonization_t>().to_json(value))
{
}
//template <
// typename jsonization_t,
// std::enable_if_t<
// std::is_rvalue_reference_v<jsonization_t&&>
// && _utils::has_move_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
// bool> = true>
//basic_object(jsonization_t&& value)
// : basic_object(
// ext::jsonization<string_t, jsonization_t>().move_to_json_object(std::move(value)))
//{
//}
~basic_object() = default;
bool empty() const noexcept { return _object_data.empty(); }
@@ -109,30 +91,6 @@ public:
template <typename value_t, template <typename...> typename map_t = std::map>
map_t<string_t, value_t> as_map() const;
template <
typename value_t,
std::enable_if_t<
_utils::has_from_json_object_in_templ_spec<value_t, string_t>::value,
bool> = true>
value_t as() const&
{
value_t res;
ext::jsonization<string_t, value_t>().from_json_object(*this, res);
return res;
}
template <
typename value_t,
std::enable_if_t<
_utils::has_move_from_json_object_in_templ_spec<value_t, string_t>::value,
bool> = true>
value_t as() &&
{
value_t res;
ext::jsonization<string_t, value_t>().move_from_json_object(std::move(*this), res);
return res;
}
// Usage: get(key_1, key_2, ..., default_value);
template <typename... key_then_default_value_t>
auto get(key_then_default_value_t&&... keys_then_default_value) const;
@@ -193,14 +151,12 @@ public:
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() const&
std::enable_if_t<_utils::has_from_json_in_member<jsonization_t, string_t>::value, bool> =
true>
explicit operator jsonization_t() const
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json(*this, dst)) {
if (!dst.from_json(*this)) {
throw exception("Wrong JSON");
}
return dst;
@@ -209,43 +165,12 @@ public:
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() const&
explicit operator jsonization_t() const
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json_object(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_move_from_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_move_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() &&
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json(std::move(*this), dst)) {
throw exception("Wrong JSON");
}
return dst;
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_move_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() &&
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().move_from_json_object(
std::move(*this),
dst)) {
if (!ext::jsonization<jsonization_t>().from_json(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
@@ -270,8 +195,8 @@ private:
template <typename string_t>
inline basic_object<string_t>::basic_object(std::initializer_list<value_type> init_list)
: _object_data(
std::make_move_iterator(init_list.begin()),
std::make_move_iterator(init_list.end()))
std::make_move_iterator(init_list.begin()),
std::make_move_iterator(init_list.end()))
{
}
@@ -384,7 +309,11 @@ template <typename string_t>
template <typename value_t, template <typename...> typename map_t>
inline map_t<string_t, value_t> basic_object<string_t>::as_map() const
{
return as<map_t<string_t, value_t>>();
map_t<string_t, value_t> result;
for (const auto& [key, val] : _object_data) {
result.emplace(key, val.template as<value_t>());
}
return result;
}
template <typename string_t>

View File

@@ -32,7 +32,7 @@ using wobject = basic_object<std::wstring>;
namespace json::ext
{
template <typename string_t, typename T, typename = void>
template <typename T>
class jsonization
{
public:
@@ -101,19 +101,11 @@ constexpr bool is_pair = false;
template <typename... args_t>
constexpr bool is_pair<std::pair<args_t...>> = true;
template <typename T, typename = void>
constexpr bool is_tuple_like = false;
template <template <typename...> typename tuple_t, typename... args_t>
constexpr bool is_tuple_like<
tuple_t<args_t...>,
std::void_t<decltype(std::tuple_size<tuple_t<args_t...>>::value)>> =
std::tuple_size<tuple_t<args_t...>>::value == sizeof...(args_t);
template <typename T>
class has_emplace_back
class has_to_json_in_member
{
template <typename U>
static auto test(int) -> decltype(std::declval<U>().emplace_back(), std::true_type());
static auto test(int) -> decltype(std::declval<U>().to_json(), std::true_type());
template <typename U>
static std::false_type test(...);
@@ -123,10 +115,11 @@ public:
};
template <typename T>
class has_to_json_in_member
class has_to_json_in_templ_spec
{
template <typename U>
static auto test(int) -> decltype(std::declval<U>().to_json(), std::true_type());
static auto test(int)
-> decltype(std::declval<ext::jsonization<U>>().to_json(std::declval<U>()), std::true_type());
template <typename U>
static std::false_type test(...);
@@ -149,6 +142,20 @@ public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_check_json_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<U>>().check_json(std::declval<json::basic_value<string_t>>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_from_json_in_member
{
@@ -163,208 +170,12 @@ public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_to_json_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().to_json(std::declval<U>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_check_json_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().check_json(std::declval<json::basic_value<string_t>>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_from_json_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().from_json(std::declval<json::basic_value<string_t>>(), std::declval<U&>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_move_to_json_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_to_json(std::declval<U>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_move_from_json_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_from_json(std::declval<json::basic_value<string_t>>(), std::declval<U&>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_to_json_array_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().to_json_array(std::declval<U>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_check_json_array_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().check_json_array(std::declval<json::basic_array<string_t>>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_from_json_array_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().from_json_array(std::declval<json::basic_array<string_t>>(), std::declval<U&>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_move_to_json_array_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_to_json_array(std::declval<U>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_move_from_json_array_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_from_json_array(std::declval<json::basic_array<string_t>>(), std::declval<U&>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_to_json_object_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().to_json_object(std::declval<U>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_check_json_object_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().check_json_object(std::declval<json::basic_object<string_t>>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_from_json_object_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().from_json_object(std::declval<json::basic_object<string_t>>(), std::declval<U&>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_move_to_json_object_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_to_json_object(std::declval<U>()), std::true_type());
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template <typename T, typename string_t>
class has_move_from_json_object_in_templ_spec
{
template <typename U>
static auto test(int)
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_from_json_object(std::declval<json::basic_object<string_t>>(), std::declval<U&>()), std::true_type());
-> decltype(std::declval<ext::jsonization<U>>().from_json(std::declval<json::basic_value<string_t>>(), std::declval<U&>()), std::true_type());
template <typename U>
static std::false_type test(...);
@@ -468,6 +279,53 @@ inline string_t to_basic_string(any_t&& arg)
}
}
} // namespace json::_utils
template <std::size_t id, typename string_t, typename variant_t>
inline bool _serialize_variant_impl(basic_value<string_t>& val, variant_t&& var)
{
if (var.index() != id) {
return false;
}
val = basic_value<string_t>(std::get<id>(std::forward<variant_t>(var)));
return true;
}
#include "../reflection/extensions.hpp"
template <typename string_t, typename variant_t, std::size_t... ids>
inline basic_value<string_t> serialize_variant(variant_t&& var, std::index_sequence<ids...>)
{
basic_value<string_t> val;
(_serialize_variant_impl<ids>(val, std::forward<variant_t>(var)) || ...);
return val;
}
template <std::size_t id, typename string_t, typename variant_t>
inline bool _deserialize_variant_impl(const basic_value<string_t>& val, variant_t& var)
{
using alt_t = std::variant_alternative_t<id, variant_t>;
if (!val.template is<alt_t>()) {
return false;
}
var = val.template as<alt_t>();
return true;
}
template <typename string_t, typename variant_t, std::size_t... ids>
inline variant_t deserialize_variant(const basic_value<string_t>& val, std::index_sequence<ids...>)
{
variant_t var;
(_deserialize_variant_impl<ids>(val, var) || ...);
return var;
}
template <typename string_t, typename variant_t, std::size_t... ids>
inline bool detect_variant(const basic_value<string_t>& val, std::index_sequence<ids...>)
{
return (val.template is<std::variant_alternative_t<ids, variant_t>>() || ...);
}
template <typename string_t, typename tuple_t, std::size_t... ids>
inline bool detect_tuple(const basic_value<string_t>& val, std::index_sequence<ids...>)
{
return val.is_array() && val.as_array().size() == std::tuple_size_v<tuple_t>
&& (val.at(ids).template is<std::tuple_element_t<ids, tuple_t>>() || ...);
}
} // namespace json::_utils

View File

@@ -4,7 +4,6 @@
#include <cstddef>
#include <initializer_list>
#include <map>
#include <memory>
#include <optional>
#include <ostream>
@@ -13,7 +12,6 @@
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
#include "exception.hpp"
#include "utils.hpp"
@@ -70,6 +68,40 @@ public:
template <typename... args_t>
basic_value(value_type type, args_t&&... args);
template <
typename collection_t,
std::enable_if_t<
_utils::is_collection<collection_t>
&& std::is_constructible_v<
typename basic_array<string_t>::value_type,
_utils::range_value_t<collection_t>>,
bool> = true>
basic_value(collection_t&& collection)
: basic_value(basic_array<string_t>(std::forward<collection_t>(collection)))
{
}
template <
typename fixed_array_t,
std::enable_if_t<_utils::is_fixed_array<fixed_array_t>, bool> = true>
basic_value(const fixed_array_t& arr)
: basic_value(basic_array<string_t>(arr))
{
}
template <
typename map_t,
std::enable_if_t<
_utils::is_map<map_t>
&& std::is_constructible_v<
typename basic_object<string_t>::value_type,
_utils::range_value_t<map_t>>,
bool> = true>
basic_value(map_t&& map)
: basic_value(basic_object<string_t>(std::forward<map_t>(map)))
{
}
template <typename enum_t, std::enable_if_t<std::is_enum_v<enum_t>, bool> = true>
basic_value(enum_t e)
: basic_value(static_cast<std::underlying_type_t<enum_t>>(e))
@@ -78,24 +110,47 @@ public:
template <
typename jsonization_t,
std::enable_if_t<_utils::has_to_json_in_templ_spec<jsonization_t, string_t>::value, bool> =
true>
std::enable_if_t<_utils::has_to_json_in_member<jsonization_t>::value, bool> = true>
basic_value(const jsonization_t& value)
: basic_value(ext::jsonization<string_t, jsonization_t>().to_json(value))
: basic_value(value.to_json())
{
}
template <
typename jsonization_t,
std::enable_if_t<
std::is_rvalue_reference_v<jsonization_t&&>
&& _utils::has_move_to_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
basic_value(jsonization_t&& value)
: basic_value(ext::jsonization<string_t, jsonization_t>().move_to_json(std::move(value)))
std::enable_if_t<_utils::has_to_json_in_templ_spec<jsonization_t>::value, bool> = true>
basic_value(const jsonization_t& value)
: basic_value(ext::jsonization<jsonization_t>().to_json(value))
{
}
template <typename... elem_ts>
basic_value(std::tuple<elem_ts...>&& tup)
: basic_value(basic_array<string_t>(std::forward<std::tuple<elem_ts...>>(tup)))
{
}
template <typename elem1_t, typename elem2_t>
basic_value(std::pair<elem1_t, elem2_t>&& pair)
: basic_value(basic_array<string_t>(std::pair<elem1_t, elem2_t>(pair)))
{
}
template <
typename variant_t,
std::enable_if_t<_utils::is_variant<std::decay_t<variant_t>>, bool> = true>
basic_value(variant_t&& var)
: basic_value(_utils::serialize_variant<string_t>(
std::forward<variant_t>(var),
std::make_index_sequence<std::variant_size_v<std::decay_t<variant_t>>>()))
{
}
template <
typename value_t,
std::enable_if_t<!std::is_convertible_v<value_t, basic_value<string_t>>, bool> = true>
basic_value(value_t) = delete;
// I don't know if you want to convert char to string or number, so I delete these constructors.
basic_value(char) = delete;
basic_value(wchar_t) = delete;
@@ -175,10 +230,7 @@ public:
map_t<string_t, value_t> as_map() const;
template <typename value_t>
value_t as() const&;
template <typename value_t>
value_t as() &&;
value_t as() const;
basic_array<string_t>& as_array();
basic_object<string_t>& as_object();
@@ -201,13 +253,13 @@ public:
basic_value<string_t>& operator=(const basic_value<string_t>& rhs);
basic_value<string_t>& operator=(basic_value<string_t>&&) noexcept;
// template <
// typename value_t,
// std::enable_if_t<std::is_convertible_v<value_t, basic_value<string_t>>, bool> = true>
// basic_value<string_t>& operator=(value_t rhs)
// {
// return *this = basic_value<string_t>(std::move(rhs));
// }
template <
typename value_t,
std::enable_if_t<std::is_convertible_v<value_t, basic_value<string_t>>, bool> = true>
basic_value<string_t>& operator=(value_t rhs)
{
return *this = basic_value<string_t>(std::move(rhs));
}
bool operator==(const basic_value<string_t>& rhs) const;
@@ -269,6 +321,16 @@ public:
return as_collection<value_t, collection_t>();
}
template <
typename value_t,
size_t Size,
template <typename, size_t> typename fixed_array_t = std::array,
std::enable_if_t<_utils::is_fixed_array<fixed_array_t<value_t, Size>>, bool> = true>
explicit operator fixed_array_t<value_t, Size>() const
{
return as_fixed_array<value_t, Size, fixed_array_t>();
}
template <
typename value_t,
template <typename...> typename map_t = std::map,
@@ -278,38 +340,57 @@ public:
return as_map<value_t, map_t>();
}
template <
typename jsonization_t,
std::enable_if_t<_utils::has_from_json_in_member<jsonization_t, string_t>::value, bool> =
true>
explicit operator jsonization_t() const
{
jsonization_t dst {};
if (!dst.from_json(*this)) {
throw exception("Wrong JSON");
}
return dst;
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() const
{
jsonization_t dst {};
if (!ext::jsonization<jsonization_t>().from_json(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
}
template <typename enum_t, std::enable_if_t<std::is_enum_v<enum_t>, bool> = true>
explicit operator enum_t() const
{
return static_cast<enum_t>(static_cast<std::underlying_type_t<enum_t>>(*this));
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() const&
template <typename... elem_ts>
explicit operator std::tuple<elem_ts...>() const
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
return as_array().template as_tuple<elem_ts...>();
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_move_from_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() &&
template <typename elem1_t, typename elem2_t>
explicit operator std::pair<elem1_t, elem2_t>() const
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().move_from_json(std::move(*this), dst)) {
throw exception("Wrong JSON");
}
return dst;
return as_array().template as_pair<elem1_t, elem2_t>();
}
template <typename... args_t>
explicit operator std::variant<args_t...>() const
{
return _utils::deserialize_variant<string_t, std::variant<args_t...>>(
*this,
std::make_index_sequence<std::variant_size_v<std::variant<args_t...>>>());
}
private:
@@ -473,8 +554,11 @@ inline bool basic_value<string_t>::is() const noexcept
if constexpr (std::is_same_v<basic_value<string_t>, value_t>) {
return true;
}
else if constexpr (_utils::has_check_json_in_member<value_t, string_t>::value) {
return value_t().check_json(*this);
}
else if constexpr (_utils::has_check_json_in_templ_spec<value_t, string_t>::value) {
return ext::jsonization<string_t, value_t>().check_json(*this);
return ext::jsonization<value_t>().check_json(*this);
}
else if constexpr (std::is_same_v<bool, value_t>) {
return is_boolean();
@@ -491,6 +575,10 @@ inline bool basic_value<string_t>::is() const noexcept
else if constexpr (_utils::is_collection<value_t>) {
return is_array() && all<typename value_t::value_type>();
}
else if constexpr (_utils::is_fixed_array<value_t>) {
return is_array() && all<typename value_t::value_type>()
&& as_array().size() == _utils::fixed_array_size<value_t>;
}
else if constexpr (std::is_same_v<basic_object<string_t>, value_t>) {
return is_object();
}
@@ -498,6 +586,21 @@ inline bool basic_value<string_t>::is() const noexcept
return is_object() && std::is_constructible_v<string_t, typename value_t::key_type>
&& all<typename value_t::mapped_type>();
}
else if constexpr (_utils::is_variant<value_t>) {
return _utils::detect_variant<string_t, value_t>(
*this,
std::make_index_sequence<std::variant_size_v<value_t>>());
}
else if constexpr (_utils::is_pair<value_t>) {
return is_array() && as_array().size() == 2
&& at(0).template is<typename value_t::first_type>()
&& at(1).template is<typename value_t::second_type>();
}
else if constexpr (_utils::is_tuple<value_t>) {
return _utils::detect_tuple<string_t, value_t>(
*this,
std::make_index_sequence<std::tuple_size_v<value_t>>());
}
else {
static_assert(!sizeof(value_t), "Unsupported type");
}
@@ -796,33 +899,21 @@ inline basic_object<string_t>& basic_value<string_t>::as_object()
template <typename string_t>
template <typename value_t>
inline value_t basic_value<string_t>::as() const&
inline value_t basic_value<string_t>::as() const
{
if constexpr (std::is_same_v<basic_value<string_t>, value_t>) {
return *this;
}
else if constexpr (_utils::has_from_json_in_templ_spec<value_t, string_t>::value) {
else if constexpr (_utils::has_from_json_in_member<value_t, string_t>::value) {
value_t dst {};
if (!ext::jsonization<string_t, value_t>().from_json(*this, dst)) {
if (!dst.from_json(*this)) {
throw exception("Wrong JSON");
}
return dst;
}
else {
return static_cast<value_t>(*this);
}
}
template <typename string_t>
template <typename value_t>
inline value_t basic_value<string_t>::as() &&
{
if constexpr (std::is_same_v<basic_value<string_t>, value_t>) {
return std::move(*this);
}
else if constexpr (_utils::has_move_from_json_in_templ_spec<value_t, string_t>::value) {
else if constexpr (_utils::has_from_json_in_templ_spec<value_t, string_t>::value) {
value_t dst {};
if (!ext::jsonization<string_t, value_t>().move_from_json(std::move(*this), dst)) {
if (!ext::jsonization<value_t>().from_json(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;

View File

@@ -2,6 +2,7 @@
// IWYU pragma: begin_exports
#include "common/serialization.hpp"
#include "common/types.hpp"
#include "parser/parser.hpp"
#include "reflection/jsonization.hpp"

8
3rdparty/include/meojson/json5.hpp vendored Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
// IWYU pragma: begin_exports
#include "common/types.hpp"
#include "parser5/parser5.hpp"
// IWYU pragma: end_exports

View File

@@ -19,7 +19,6 @@ namespace json
// ****************************
template <
bool accept_jsonc = false,
typename string_t = default_string_t,
typename parsing_t = void,
typename accel_traits = _packed_bytes::packed_bytes_trait_max>
@@ -57,7 +56,6 @@ private:
bool skip_string_literal_with_accel();
bool skip_whitespace() noexcept;
bool skip_comment() noexcept;
bool skip_digit();
bool skip_unicode_escape(uint16_t& pair_high, string_t& result);
@@ -76,20 +74,14 @@ auto parse(const parsing_t& content);
template <typename char_t>
auto parse(char_t* content);
template <typename parsing_t>
auto parsec(const parsing_t& content);
template <typename char_t>
auto parsec(char_t* content);
template <
typename istream_t,
typename = std::enable_if_t<
std::is_base_of_v<std::basic_istream<typename istream_t::char_type>, istream_t>>>
auto parse(istream_t& istream, bool check_bom = false, bool with_commets = false);
auto parse(istream_t& istream, bool check_bom);
template <typename ifstream_t = std::ifstream, typename path_t = void>
auto open(const path_t& path, bool check_bom = false, bool with_commets = false);
auto open(const path_t& path, bool check_bom = false);
namespace literals
{
@@ -113,17 +105,15 @@ const basic_value<string_t> invalid_value();
// * parser impl *
// *************************
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
template <typename string_t, typename parsing_t, typename accel_traits>
inline std::optional<basic_value<string_t>>
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse(const parsing_t& content)
parser<string_t, parsing_t, accel_traits>::parse(const parsing_t& content)
{
return parser<accept_jsonc, string_t, parsing_t, accel_traits>(content.cbegin(), content.cend())
.parse();
return parser<string_t, parsing_t, accel_traits>(content.cbegin(), content.cend()).parse();
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline std::optional<basic_value<string_t>>
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse()
template <typename string_t, typename parsing_t, typename accel_traits>
inline std::optional<basic_value<string_t>> parser<string_t, parsing_t, accel_traits>::parse()
{
if (!skip_whitespace()) {
return std::nullopt;
@@ -145,7 +135,8 @@ inline std::optional<basic_value<string_t>>
return std::nullopt;
}
// After the parsing is complete, there should be no more content other than spaces behind
// After the parsing is complete, there should be no more content other than
// spaces behind
if (skip_whitespace()) {
return std::nullopt;
}
@@ -153,8 +144,8 @@ inline std::optional<basic_value<string_t>>
return result_value;
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_value()
template <typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<string_t, parsing_t, accel_traits>::parse_value()
{
switch (*_cur) {
case 'n':
@@ -185,8 +176,8 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
}
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_null()
template <typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<string_t, parsing_t, accel_traits>::parse_null()
{
for (const auto& ch : _utils::null_string<string_t>()) {
if (_cur != _end && *_cur == ch) {
@@ -200,9 +191,8 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
return basic_value<string_t>();
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t>
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_boolean()
template <typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<string_t, parsing_t, accel_traits>::parse_boolean()
{
switch (*_cur) {
case 't':
@@ -230,8 +220,8 @@ inline basic_value<string_t>
}
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_number()
template <typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<string_t, parsing_t, accel_traits>::parse_number()
{
const auto first = _cur;
if (*_cur == '-') {
@@ -269,8 +259,8 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
return basic_value<string_t>(basic_value<string_t>::value_type::number, string_t(first, _cur));
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_string()
template <typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<string_t, parsing_t, accel_traits>::parse_string()
{
auto string_opt = parse_stdstring();
if (!string_opt) {
@@ -281,8 +271,8 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
std::move(string_opt).value());
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_array()
template <typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<string_t, parsing_t, accel_traits>::parse_array()
{
if (*_cur == '[') {
++_cur;
@@ -306,12 +296,6 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
return invalid_value<string_t>();
}
if constexpr (accept_jsonc) {
if (*_cur == ']') {
break;
}
}
basic_value<string_t> val = parse_value();
if (!val.valid() || !skip_whitespace()) {
@@ -338,8 +322,8 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
return basic_array<string_t>(std::move(result));
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_object()
template <typename string_t, typename parsing_t, typename accel_traits>
inline basic_value<string_t> parser<string_t, parsing_t, accel_traits>::parse_object()
{
if (*_cur == '{') {
++_cur;
@@ -363,12 +347,6 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
return invalid_value<string_t>();
}
if constexpr (accept_jsonc) {
if (*_cur == '}') {
break;
}
}
auto key_opt = parse_stdstring();
if (key_opt && skip_whitespace() && *_cur == ':') {
@@ -411,9 +389,8 @@ inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_tra
return basic_object<string_t>(std::move(result));
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline std::optional<string_t>
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_stdstring()
template <typename string_t, typename parsing_t, typename accel_traits>
inline std::optional<string_t> parser<string_t, parsing_t, accel_traits>::parse_stdstring()
{
if (*_cur == '"') {
++_cur;
@@ -500,8 +477,8 @@ inline std::optional<string_t>
return std::nullopt;
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_unicode_escape(
template <typename string_t, typename parsing_t, typename accel_traits>
inline bool parser<string_t, parsing_t, accel_traits>::skip_unicode_escape(
uint16_t& pair_high,
string_t& result)
{
@@ -597,9 +574,8 @@ inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_unicod
return true;
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline bool
parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_string_literal_with_accel()
template <typename string_t, typename parsing_t, typename accel_traits>
inline bool parser<string_t, parsing_t, accel_traits>::skip_string_literal_with_accel()
{
if constexpr (sizeof(*_cur) != 1) {
return false;
@@ -626,8 +602,8 @@ inline bool
return _cur != _end;
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_whitespace() noexcept
template <typename string_t, typename parsing_t, typename accel_traits>
inline bool parser<string_t, parsing_t, accel_traits>::skip_whitespace() noexcept
{
while (_cur != _end) {
switch (*_cur) {
@@ -637,17 +613,6 @@ inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_whites
case '\n':
++_cur;
break;
case '/':
if constexpr (accept_jsonc) {
if (!skip_comment()) {
return false;
}
// else continue;
}
else {
return false;
}
break;
case '\0':
return false;
default:
@@ -657,59 +622,8 @@ inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_whites
return false;
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
bool json::parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_comment() noexcept
{
if (_cur == _end || *_cur != '/') {
return false;
}
if (++_cur == _end) {
return false;
}
enum class comment_type
{
invalid,
line,
block,
} t = comment_type::invalid;
switch (*_cur++) {
case '/':
t = comment_type::line;
break;
case '*':
t = comment_type::block;
break;
default:
return false;
}
while (_cur != _end) {
switch (*_cur++) {
case '\n':
if (t == comment_type::line) {
return true;
}
break;
case '*':
if (t == comment_type::block && _cur != _end && *_cur == '/') {
++_cur;
return true;
}
break;
default:
break;
}
}
// _cur == _end
return t == comment_type::line;
}
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_digit()
template <typename string_t, typename parsing_t, typename accel_traits>
inline bool parser<string_t, parsing_t, accel_traits>::skip_digit()
{
// At least one digit
if (_cur != _end && std::isdigit(*_cur)) {
@@ -739,7 +653,7 @@ template <typename parsing_t>
auto parse(const parsing_t& content)
{
using string_t = std::basic_string<typename parsing_t::value_type>;
return parser<false, string_t, parsing_t>::parse(content);
return parser<string_t, parsing_t>::parse(content);
}
template <typename char_t>
@@ -749,7 +663,7 @@ auto parse(char_t* content)
}
template <typename istream_t, typename _>
auto parse(istream_t& ifs, bool check_bom, bool with_commets)
auto parse(istream_t& ifs, bool check_bom)
{
using string_t = std::basic_string<typename istream_t::char_type>;
@@ -772,11 +686,11 @@ auto parse(istream_t& ifs, bool check_bom, bool with_commets)
str.assign(str.begin() + 3, str.end());
}
}
return with_commets ? parsec(str) : parse(str);
return parse(str);
}
template <typename ifstream_t, typename path_t>
auto open(const path_t& filepath, bool check_bom, bool with_commets)
auto open(const path_t& filepath, bool check_bom)
{
using char_t = typename ifstream_t::char_type;
using string_t = std::basic_string<char_t>;
@@ -787,24 +701,11 @@ auto open(const path_t& filepath, bool check_bom, bool with_commets)
if (!ifs.is_open()) {
return return_t(std::nullopt);
}
auto opt = parse(ifs, check_bom, with_commets);
auto opt = parse(ifs, check_bom);
ifs.close();
return opt;
}
template <typename parsing_t>
auto parsec(const parsing_t& content)
{
using string_t = std::basic_string<typename parsing_t::value_type>;
return parser<true, string_t, parsing_t>::parse(content);
}
template <typename char_t>
auto parsec(char_t* content)
{
return parsec(std::basic_string_view<std::decay_t<char_t>> { content });
}
namespace literals
{
inline value operator""_json(const char* str, size_t len)

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,656 +0,0 @@
// IWYU pragma: private, include <meojson/json.hpp>
#pragma once
#include <cstddef>
#include <filesystem>
#include <queue>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
#include "../common/types.hpp"
namespace json::ext
{
template <typename string_t, typename impl_t, typename var_t, size_t len> // (size_t)-1 for no
// restriction
class __jsonization_array
{
public:
json::basic_value<string_t> to_json(const var_t& value) const
{
return static_cast<const impl_t*>(this)->to_json_array(value);
}
bool check_json(const json::basic_value<string_t>& json) const
{
if (!json.is_array()) {
return false;
}
const auto& arr = json.as_array();
if constexpr (len != static_cast<size_t>(-1)) {
if (len != arr.size()) {
return false;
}
}
return static_cast<const impl_t*>(this)->check_json_array(arr);
}
bool from_json(const json::basic_value<string_t>& json, var_t& value) const
{
if (!json.is_array()) {
return false;
}
const auto& arr = json.as_array();
if constexpr (len != static_cast<size_t>(-1)) {
if (len != arr.size()) {
return false;
}
}
return static_cast<const impl_t*>(this)->from_json_array(arr, value);
}
json::basic_value<string_t> move_to_json(var_t value) const
{
return static_cast<const impl_t*>(this)->move_to_json_array(std::move(value));
}
bool move_from_json(json::basic_value<string_t> json, var_t& value) const
{
if (!json.is_array()) {
return false;
}
auto& arr = json.as_array();
if constexpr (len != static_cast<size_t>(-1)) {
if (len != arr.size()) {
return false;
}
}
return static_cast<const impl_t*>(this)->move_from_json_array(std::move(arr), value);
}
};
template <typename string_t, typename impl_t, typename var_t>
class __jsonization_object
{
public:
json::basic_value<string_t> to_json(const var_t& value) const
{
return static_cast<const impl_t*>(this)->to_json_object(value);
}
bool check_json(const json::basic_value<string_t>& json) const
{
if (!json.is_object()) {
return false;
}
const auto& obj = json.as_object();
return static_cast<const impl_t*>(this)->check_json_object(obj);
}
bool from_json(const json::basic_value<string_t>& json, var_t& value) const
{
if (!json.is_object()) {
return false;
}
const auto& obj = json.as_object();
return static_cast<const impl_t*>(this)->from_json_object(obj, value);
}
json::basic_value<string_t> move_to_json(var_t value) const
{
return static_cast<const impl_t*>(this)->move_to_json_object(std::move(value));
}
bool move_from_json(json::basic_value<string_t> json, var_t& value) const
{
if (!json.is_object()) {
return false;
}
auto& obj = json.as_object();
return static_cast<const impl_t*>(this)->move_from_json_object(std::move(obj), value);
}
};
template <typename string_t>
class jsonization<string_t, std::nullptr_t>
{
public:
json::basic_value<string_t> to_json(const std::nullptr_t&) const
{
return json::basic_value<string_t> {};
}
bool check_json(const json::basic_value<string_t>& json) const { return json.is_null(); }
bool from_json(const json::basic_value<string_t>& json, std::nullptr_t&)
{
return check_json(json);
}
};
template <typename string_t>
class jsonization<
string_t,
std::filesystem::path,
std::enable_if_t<
std::is_same_v<string_t, std::filesystem::path::string_type>
|| std::is_same_v<string_t, std::string>>>
{
public:
json::basic_value<string_t> to_json(const std::filesystem::path& path) const
{
if constexpr (std::is_same_v<string_t, std::filesystem::path::string_type>) {
return path.native();
}
else if constexpr (std::is_same_v<string_t, std::string>) {
#if __cplusplus >= 202002L
std::u8string u8str = path.u8string();
return std::string { u8str.begin(), u8str.end() };
#else
return path.u8string();
#endif
}
#if __cplusplus >= 202002L
else if constexpr (std::is_same_v<string_t, std::u8string>) {
return path.u8string();
}
#endif
}
bool check_json(const json::basic_value<string_t>& json) const { return json.is_string(); }
bool from_json(const json::basic_value<string_t>& json, std::filesystem::path& path) const
{
path = json.as_string();
return true;
}
};
template <
typename string_t,
template <typename, size_t> typename arr_t,
typename value_t,
size_t size>
class jsonization<string_t, arr_t<value_t, size>>
: public __jsonization_array<
string_t,
jsonization<string_t, arr_t<value_t, size>>,
arr_t<value_t, size>,
size>
{
public:
json::basic_array<string_t> to_json_array(const arr_t<value_t, size>& value) const
{
json::basic_array<string_t> result;
for (size_t i = 0; i < size; i++) {
result.emplace_back(value.at(i));
}
return result;
}
bool check_json_array(const json::basic_array<string_t>& arr) const
{
return arr.template all<value_t>();
}
bool from_json_array(const json::basic_array<string_t>& arr, arr_t<value_t, size>& value) const
{
if (!check_json_array(arr)) {
return false;
}
for (size_t i = 0; i < size; i++) {
value.at(i) = arr[i].template as<value_t>();
}
return true;
}
json::basic_array<string_t> move_to_json_array(arr_t<value_t, size> value) const
{
json::basic_array<string_t> result;
for (size_t i = 0; i < size; i++) {
result.emplace_back(std::move(value.at(i)));
}
return result;
}
bool move_from_json_array(json::basic_array<string_t> arr, arr_t<value_t, size>& value) const
{
if (!check_json_array(arr)) {
return false;
}
for (size_t i = 0; i < size; i++) {
value.at(i) = std::move(arr[i]).template as<value_t>();
}
return true;
}
};
template <typename string_t, typename collection_t>
class jsonization<string_t, collection_t, std::enable_if_t<_utils::is_collection<collection_t>>>
: public __jsonization_array<
string_t,
jsonization<string_t, collection_t>,
collection_t,
(size_t)-1>
{
public:
json::basic_array<string_t> to_json_array(const collection_t& value) const
{
json::basic_array<string_t> result;
for (const auto& val : value) {
result.emplace_back(val);
}
return result;
}
bool check_json_array(const json::basic_array<string_t>& arr) const
{
return arr.template all<typename collection_t::value_type>();
}
bool from_json_array(const json::basic_array<string_t>& arr, collection_t& value) const
{
if (!check_json_array(arr)) {
return false;
}
value = {};
for (const auto& val : arr) {
if constexpr (_utils::has_emplace_back<collection_t>::value) {
value.emplace_back(val.template as<typename collection_t::value_type>());
}
else {
value.emplace(val.template as<typename collection_t::value_type>());
}
}
return true;
}
json::basic_array<string_t> move_to_json_array(collection_t value) const
{
json::basic_array<string_t> result;
for (auto& val : value) {
result.emplace_back(std::move(val));
}
return result;
}
bool move_from_json_array(json::basic_array<string_t> arr, collection_t& value) const
{
if (!check_json_array(arr)) {
return false;
}
for (auto& val : arr) {
if constexpr (_utils::has_emplace_back<collection_t>::value) {
value.emplace_back(std::move(val).template as<typename collection_t::value_type>());
}
else {
value.emplace(std::move(val).template as<typename collection_t::value_type>());
}
}
return true;
}
};
template <typename string_t, template <typename...> typename tuple_t, typename... args_t>
class jsonization<
string_t,
tuple_t<args_t...>,
std::enable_if_t<_utils::is_tuple_like<tuple_t<args_t...>>>>
: public __jsonization_array<
string_t,
jsonization<string_t, tuple_t<args_t...>>,
tuple_t<args_t...>,
std::tuple_size_v<tuple_t<args_t...>>>
{
public:
constexpr static size_t tuple_size = std::tuple_size_v<tuple_t<args_t...>>;
json::basic_array<string_t> to_json_array(const tuple_t<args_t...>& value) const
{
json::basic_array<string_t> result;
to_json_impl(result, value, std::make_index_sequence<tuple_size>());
return result;
}
template <std::size_t... Is>
void to_json_impl(
json::basic_array<string_t>& arr,
const tuple_t<args_t...>& t,
std::index_sequence<Is...>) const
{
using std::get;
(arr.emplace_back(get<Is>(t)), ...);
}
bool check_json_array(const json::basic_array<string_t>& arr) const
{
return check_json_impl(arr, std::make_index_sequence<tuple_size>());
}
template <std::size_t... Is>
bool check_json_impl(const json::basic_array<string_t>& arr, std::index_sequence<Is...>) const
{
return (arr[Is].template is<std::tuple_element_t<Is, tuple_t<args_t...>>>() && ...);
}
bool from_json_array(const json::basic_array<string_t>& arr, tuple_t<args_t...>& value) const
{
if (!check_json_array(arr)) {
return false;
}
from_json_impl(arr, value, std::make_index_sequence<tuple_size>());
return true;
}
template <std::size_t... Is>
void from_json_impl(
const json::basic_array<string_t>& arr,
tuple_t<args_t...>& t,
std::index_sequence<Is...>) const
{
using std::get;
((get<Is>(t) = arr[Is].template as<std::tuple_element_t<Is, tuple_t<args_t...>>>()), ...);
}
json::basic_array<string_t> move_to_json_array(tuple_t<args_t...> value) const
{
json::basic_array<string_t> result;
move_to_json_impl(result, std::move(value), std::make_index_sequence<tuple_size>());
return result;
}
template <std::size_t... Is>
void move_to_json_impl(
json::basic_array<string_t>& arr,
tuple_t<args_t...> t,
std::index_sequence<Is...>) const
{
using std::get;
(arr.emplace_back(std::move(get<Is>(t))), ...);
}
bool move_from_json_array(json::basic_array<string_t> arr, tuple_t<args_t...>& value) const
{
if (!check_json_array(arr)) {
return false;
}
move_from_json_impl(arr, value, std::make_index_sequence<tuple_size>());
return true;
}
template <std::size_t... Is>
void move_from_json_impl(
json::basic_array<string_t> arr,
tuple_t<args_t...>& t,
std::index_sequence<Is...>) const
{
using std::get;
((get<Is>(t) =
std::move(arr[Is]).template as<std::tuple_element_t<Is, tuple_t<args_t...>>>()),
...);
}
};
template <typename string_t, typename map_t>
class jsonization<
string_t,
map_t,
std::enable_if_t<_utils::is_map<map_t> && std::is_same_v<typename map_t::key_type, string_t>>>
: public __jsonization_object<string_t, jsonization<string_t, map_t>, map_t>
{
public:
json::basic_object<string_t> to_json_object(const map_t& value) const
{
json::basic_object<string_t> result;
for (const auto& [key, val] : value) {
result.emplace(key, val);
}
return result;
}
bool check_json_object(const json::basic_object<string_t>& arr) const
{
for (const auto& [key, val] : arr) {
if (!val.template is<typename map_t::mapped_type>()) {
return false;
}
}
return true;
}
bool from_json_object(const json::basic_object<string_t>& arr, map_t& value) const
{
// TODO: 是不是直接from不check了算了
if (!check_json_object(arr)) {
return false;
}
value = {};
for (const auto& [key, val] : arr) {
value.emplace(key, val.template as<typename map_t::mapped_type>());
}
return true;
}
json::basic_object<string_t> move_to_json_object(map_t value) const
{
json::basic_object<string_t> result;
for (auto& [key, val] : value) {
result.emplace(key, std::move(val));
}
return result;
}
bool move_from_json_object(json::basic_object<string_t> arr, map_t& value) const
{
// TODO: 是不是直接from不check了算了
if (!check_json_object(arr)) {
return false;
}
value = {};
for (auto& [key, val] : arr) {
value.emplace(key, std::move(val).template as<typename map_t::mapped_type>());
}
return true;
}
};
template <typename string_t, typename... args_t>
class jsonization<string_t, std::variant<args_t...>>
{
public:
using variant_t = std::variant<args_t...>;
constexpr static size_t variant_size = std::variant_size_v<variant_t>;
json::basic_value<string_t> to_json(const variant_t& value) const
{
json::basic_value<string_t> result;
to_json_impl(result, value, std::make_index_sequence<variant_size>());
return result;
}
template <std::size_t... Is>
void to_json_impl(
json::basic_value<string_t>& val,
const variant_t& t,
std::index_sequence<Is...>) const
{
using std::get;
std::ignore = ((t.index() == Is ? (val = get<Is>(t), true) : false) || ...);
}
bool check_json(const json::basic_value<string_t>& json) const
{
return check_json_impl(json, std::make_index_sequence<variant_size>());
}
template <std::size_t... Is>
bool check_json_impl(const json::basic_value<string_t>& val, std::index_sequence<Is...>) const
{
return (val.template is<std::variant_alternative_t<Is, variant_t>>() || ...);
}
bool from_json(const json::basic_value<string_t>& json, variant_t& value) const
{
if (!check_json_impl(json, std::make_index_sequence<variant_size>())) {
return false;
}
from_json_impl(json, value, std::make_index_sequence<variant_size>());
return true;
}
template <std::size_t... Is>
void from_json_impl(
const json::basic_value<string_t>& json,
variant_t& t,
std::index_sequence<Is...>) const
{
std::ignore =
((json.template is<std::variant_alternative_t<Is, variant_t>>()
? (t = json.template as<std::variant_alternative_t<Is, variant_t>>(), true)
: false)
|| ...);
}
json::basic_value<string_t> move_to_json(variant_t value) const
{
json::basic_value<string_t> result;
move_to_json_impl(result, std::move(value), std::make_index_sequence<variant_size>());
return result;
}
template <std::size_t... Is>
void
move_to_json_impl(json::basic_value<string_t>& val, variant_t t, std::index_sequence<Is...>)
const
{
using std::get;
std::ignore = ((t.index() == Is ? (val = std::move(get<Is>(t)), true) : false) || ...);
}
bool move_from_json(json::basic_value<string_t> json, variant_t& value) const
{
if (!check_json_impl(json, std::make_index_sequence<variant_size>())) {
return false;
}
move_from_json_impl(std::move(json), value, std::make_index_sequence<variant_size>());
return true;
}
template <std::size_t... Is>
void move_from_json_impl(
json::basic_value<string_t> json,
variant_t& t,
std::index_sequence<Is...>) const
{
std::ignore =
((json.template is<std::variant_alternative_t<Is, variant_t>>()
? (t = std::move(json).template as<std::variant_alternative_t<Is, variant_t>>(),
true)
: false)
|| ...);
}
};
// TODO: check if has move_xxx in member
template <typename string_t, typename var_t>
class jsonization<
string_t,
var_t,
std::enable_if_t<
_utils::has_to_json_in_member<var_t>::value
&& _utils::has_check_json_in_member<var_t, string_t>::value
&& _utils::has_from_json_in_member<var_t, string_t>::value>>
{
public:
json::basic_value<string_t> to_json(const var_t& value) const { return value.to_json(); }
bool check_json(const json::basic_value<string_t>& json) const
{
var_t value;
return value.check_json(json);
}
bool from_json(const json::basic_value<string_t>& json, var_t& value) const
{
return value.from_json(json);
}
json::basic_value<string_t> move_to_json(var_t value) const { return to_json(value); }
bool move_from_json(json::basic_value<string_t> json, var_t& value) const
{
return from_json(json, value);
}
};
// really need this fucking queue?
template <typename string_t, typename value_t>
class jsonization<string_t, std::queue<value_t>>
: public __jsonization_array<
string_t,
jsonization<string_t, std::queue<value_t>>,
std::queue<value_t>,
(size_t)-1>
{
public:
json::basic_array<string_t> to_json_array(const std::queue<value_t>& value) const
{
return move_to_json_array(value);
}
bool check_json_array(const json::basic_array<string_t>& arr) const
{
return arr.template all<value_t>();
}
bool from_json_array(const json::basic_array<string_t>& arr, std::queue<value_t>& value) const
{
if (!check_json_array(arr)) {
return false;
}
value = {};
for (const auto& val : arr) {
value.emplace(val.template as<value_t>());
}
return true;
}
json::basic_array<string_t> move_to_json_array(std::queue<value_t> value) const
{
json::basic_array<string_t> result;
while (!value.empty()) {
result.emplace_back(std::move(value.front()));
value.pop();
}
return result;
}
bool move_from_json_array(json::basic_array<string_t> arr, std::queue<value_t>& value) const
{
if (!check_json_array(arr)) {
return false;
}
for (auto& val : arr) {
value.emplace(std::move(val).template as<value_t>());
}
return true;
}
};
}

View File

@@ -4,295 +4,123 @@
#include <string>
#include <type_traits>
#include <utility>
#include "../common/types.hpp"
#include "extensions.hpp"
namespace json::_jsonization_helper
{
template <typename value_t>
struct is_optional_t : public std::false_type
{
};
template <typename value_t>
struct is_optional_t<std::optional<value_t>> : public std::true_type
{
};
template <typename value_t>
inline constexpr bool is_optional_v = is_optional_t<value_t>::value;
struct next_is_optional_t
{
};
struct next_override_key_t
{
const char* key;
};
struct next_state_t
{
bool is_optional = false;
const char* override_key = nullptr;
};
struct va_arg_end
{
};
template <typename tag_t>
struct is_tag_t : public std::false_type
{
};
template <>
struct is_tag_t<next_is_optional_t> : public std::true_type
{
};
template <>
struct is_tag_t<next_override_key_t> : public std::true_type
{
};
struct dumper
{
void _to_json(json::object&, va_arg_end) const {}
template <typename... rest_t>
void _to_json(json::object& result, const char* key, rest_t&&... rest) const
template <typename var_t, typename... rest_t>
json::value _to_json(const char* key, const var_t& var, rest_t&&... rest) const
{
_to_json(result, next_state_t {}, key, std::forward<rest_t>(rest)...);
}
template <
typename var_t,
typename... rest_t,
typename _ = std::enable_if_t<!is_tag_t<var_t>::value, void>>
void _to_json(
json::object& result,
next_state_t state,
const char* key,
const var_t& var,
rest_t&&... rest) const
{
if (state.override_key) {
key = state.override_key;
}
if constexpr (is_optional_v<var_t>) {
if (!state.is_optional) {
throw exception("std::optional must be used with MEO_OPT");
}
if (var.has_value()) {
result.emplace(key, var.value());
}
}
else {
result.emplace(key, var);
}
_to_json(result, std::forward<rest_t>(rest)...);
json::value result = _to_json(std::forward<rest_t>(rest)...);
result.emplace(key, var);
return result;
}
template <typename... rest_t>
void _to_json(
json::object& result,
next_state_t state,
const char*,
next_is_optional_t,
rest_t&&... rest) const
json::value _to_json(const char*, next_is_optional_t, rest_t&&... rest) const
{
state.is_optional = true;
_to_json(result, state, std::forward<rest_t>(rest)...);
return _to_json(std::forward<rest_t>(rest)...);
}
template <typename... rest_t>
void _to_json(
json::object& result,
next_state_t state,
const char*,
next_override_key_t override_key,
rest_t&&... rest) const
{
state.override_key = override_key.key;
_to_json(result, state, std::forward<rest_t>(rest)...);
}
json::value _to_json(va_arg_end) const { return {}; }
};
struct checker
{
bool _check_json(const json::value&, std::string&, va_arg_end) const { return true; }
template <typename... rest_t>
template <typename var_t, typename... rest_t>
bool _check_json(
const json::value& in,
std::string& error_key,
const char* key,
rest_t&&... rest) const
{
return _check_json(in, error_key, next_state_t {}, key, std::forward<rest_t>(rest)...);
}
template <
typename var_t,
typename... rest_t,
typename _ = std::enable_if_t<!is_tag_t<var_t>::value, void>>
bool _check_json(
const json::value& in,
std::string& error_key,
next_state_t state,
const char* key,
const var_t&,
rest_t&&... rest) const
{
if (state.override_key) {
key = state.override_key;
}
auto opt = in.find(key);
if constexpr (is_optional_v<var_t>) {
if (!state.is_optional) {
throw exception("std::optional must be used with MEO_OPT");
}
if (opt && !opt->is<typename var_t::value_type>()) {
error_key = key;
return false;
}
}
else {
if (state.is_optional) {
if (opt && !opt->is<var_t>()) {
error_key = key;
return false;
} // is_optional, ignore key not found
}
else if (!opt || !opt->is<var_t>()) {
error_key = key;
return false;
}
if (!opt || !opt->is<var_t>()) {
error_key = key;
return false;
}
return _check_json(in, error_key, std::forward<rest_t>(rest)...);
}
template <typename... rest_t>
template <typename var_t, typename... rest_t>
bool _check_json(
const json::value& in,
std::string& error_key,
next_state_t state,
const char*,
next_is_optional_t,
const char* key,
const var_t&,
rest_t&&... rest) const
{
state.is_optional = true;
return _check_json(in, error_key, state, std::forward<rest_t>(rest)...);
auto opt = in.find(key);
if (opt) {
if (!opt->is<var_t>()) {
error_key = key;
return false;
}
} // next_is_optional_t, ignore key not found
return _check_json(in, error_key, std::forward<rest_t>(rest)...);
}
template <typename... rest_t>
bool _check_json(
const json::value& in,
std::string& error_key,
next_state_t state,
const char*,
next_override_key_t override_key,
rest_t&&... rest) const
{
state.override_key = override_key.key;
return _check_json(in, error_key, state, std::forward<rest_t>(rest)...);
}
bool _check_json(const json::value&, std::string&, va_arg_end) const { return true; }
};
struct loader
{
bool _from_json(const json::value&, std::string&, va_arg_end) const { return true; }
template <typename... rest_t>
bool
_from_json(const json::value& in, std::string& error_key, const char* key, rest_t&&... rest)
{
return _from_json(in, error_key, next_state_t {}, key, std::forward<rest_t>(rest)...);
}
template <
typename var_t,
typename... rest_t,
typename _ = std::enable_if_t<!is_tag_t<var_t>::value, void>>
template <typename var_t, typename... rest_t>
bool _from_json(
const json::value& in,
std::string& error_key,
next_state_t state,
const char* key,
var_t& var,
rest_t&&... rest)
rest_t&&... rest) const
{
if (state.override_key) {
key = state.override_key;
}
auto opt = in.find(key);
if constexpr (is_optional_v<var_t>) {
if (!state.is_optional) {
throw exception("std::optional must be used with MEO_OPT");
}
if (opt && !opt->is<typename var_t::value_type>()) {
error_key = key;
return false;
}
if (opt) {
var = std::move(opt)->as<typename var_t::value_type>();
}
else {
var = std::nullopt;
}
}
else {
if (state.is_optional) {
if (opt && !opt->is<var_t>()) {
error_key = key;
return false;
} // is_optional, ignore key not found
}
else if (!opt || !opt->is<var_t>()) {
error_key = key;
return false;
}
if (opt) {
var = std::move(opt)->as<var_t>();
}
if (!opt || !opt->is<var_t>()) {
error_key = key;
return false;
}
var = std::move(opt)->as<var_t>();
return _from_json(in, error_key, std::forward<rest_t>(rest)...);
}
template <typename... rest_t>
template <typename var_t, typename... rest_t>
bool _from_json(
const json::value& in,
std::string& error_key,
next_state_t state,
const char*,
next_is_optional_t,
rest_t&&... rest)
const char* key,
var_t& var,
rest_t&&... rest) const
{
state.is_optional = true;
return _from_json(in, error_key, state, std::forward<rest_t>(rest)...);
auto opt = in.find(key);
if (opt) {
if (!opt->is<var_t>()) {
error_key = key;
return false;
}
var = std::move(opt)->as<var_t>();
} // next_is_optional_t, ignore key not found
return _from_json(in, error_key, std::forward<rest_t>(rest)...);
}
template <typename... rest_t>
bool _from_json(
const json::value& in,
std::string& error_key,
next_state_t state,
const char*,
next_override_key_t override_key,
rest_t&&... rest)
{
state.override_key = override_key.key;
return _from_json(in, error_key, state, std::forward<rest_t>(rest)...);
}
bool _from_json(const json::value&, std::string&, va_arg_end) const { return true; }
};
} // namespace json::_jsonization_helper
@@ -313,7 +141,8 @@ namespace json::_private_macro
#define _MEOJSON_EXPAND(x) x
#define _MEOJSON_FOR_EACH_1(pred, x) pred(x)
#define _MEOJSON_FOR_EACH_0(pred, ...)
#define _MEOJSON_FOR_EACH_1(pred, x, ...) pred(x)
#define _MEOJSON_FOR_EACH_2(pred, x, ...) \
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_1(pred, __VA_ARGS__))
#define _MEOJSON_FOR_EACH_3(pred, x, ...) \
@@ -593,12 +422,9 @@ namespace json::_private_macro
#define MEO_TOJSON(...) \
json::value to_json() const \
{ \
json::object result; \
json::_jsonization_helper::dumper()._to_json( \
result, \
return json::_jsonization_helper::dumper()._to_json( \
_MEOJSON_EXPAND(_MEOJSON_FOR_EACH(_MEOJSON_KEY_VALUE, __VA_ARGS__)) \
json::_jsonization_helper::va_arg_end {}); \
return result; \
}
#define MEO_CHECKJSON(...) \
@@ -641,7 +467,6 @@ namespace json::_private_macro
_MEOJSON_EXPAND(MEO_FROMJSON(__VA_ARGS__))
#define MEO_OPT json::_jsonization_helper::next_is_optional_t {},
#define MEO_KEY(key) json::_jsonization_helper::next_override_key_t { key },
#if defined(__clang__)
#pragma clang diagnostic pop // -Wgnu-zero-variadic-macro-arguments

View File

@@ -1,234 +1,48 @@
## v5.24.2
### 特殊说明
由于本次活动代号 SS 与 SideStory 的内部代号冲突,关卡命名统一采用 AveMujica-x 格式(例如 AveMujica-8请使用 手动输入关卡名 / cli 的博士使用此代号。
### 功能进化 | Highlight
本次更新继续扩展自动化能力,一起来看看吧
#### 自动战斗优化
这个版本我们优化了自动战斗功能,现在你可以在更多的场景下使用自动战斗功能。目前 MAA 支持以下场景:
* `主线/故事集/SideStory`:基础模式,注意只能在当前章节/页面内导航(即 SS 里不能用于切换普通关、EX 关和 S 关);
* `保全派驻`:用于保全派驻模式,可以点击神秘代码输入框右侧的向下小箭头来选择内置作业,并且可以设置循环次数;
* `悖论模拟`:新增的专用于干员悖论模拟的场景,分为以下两种使用方式:
* 直接使用单次战斗:输入神秘代码后,在干员的悖论模拟入口,<u>选择好技能,出现【开始模拟】按钮后,点击 MAA 的开始按钮</u>
* 多个干员连续作战:右键粘贴按钮可以粘贴作业集的神秘代码(或是勾选战斗列表依次输入每个干员的作业的神秘代码),然后<u>在干员列表界面,点击 MAA 的开始按钮</u>。
* `其他活动`:兜底模式,不可使用战斗列表。
现在,博士们可以直接使用悖论模拟的战斗列表功能完成所有悖论模拟作业,支持按职业找人、自动跳过未拥有的干员,并在战斗列表中直接显示干员名,真正实现“点一下,全都打完”~
#### 新内容支持
- **争锋频道:蜜果城** 入口适配(本质还是跑的青草城代码)
- 外服也同步适配了 **新版终端界面**
#### 其他优化
- 自动战斗在关卡结束后增加了黑色返回按钮的检测,更加稳健
- 界面与交互细节继续优化,深色模式显示效果更自然
----
### [CN ONLY] Special Notice
Due to a conflict between this event's code SS and the internal code for SideStory, the stage naming will use the format AveMujica-x (e.g., AveMujica-8). Please use this code when entering the stage manually or via CLI.
#### Copilot Optimization
In this version, we've optimized the Copilot, allowing you to use it in more scenarios. Currently, MAA supports the following scenarios:
* `Main Theme/Intermezzi/SideStory`: Basic mode. Note that navigation is only possible within the current chapter/page (i.e., in SideStory, you cannot switch between normal stages, EX stages, and S stages);
* `SSS`: For SSS mode. You can click the small downward arrow on the right side of the mysterious code input box to select built-in files, also you can set the number of loop times;
* `Paradox Simulation`: A newly added scenario specifically designed for operator paradox simulations, available in the following two usage methods:
* Direct single battle usage: After entering the secret code, you need to navigate to the operator's paradox simulation entry point, <u>select the skills, wait for the [Start Simulation] button to appear, then click MAA's start button</u> to start;
* Continuous battles for multiple operators: You need to rightclick the paste button to paste the mysterious code for the job set, or check the battle list checkbox and sequentially enter each operator's mysterious code for the operation, then <u>click MAA's start button on the operator list interface</u>.
* `Other Events`: Fallback mode, battle list cannot be used.
Now, Doctors can directly use the combat list feature in Paradox Simulation to complete all Paradox Simulation assignments. It supports filtering by profession, automatically skipping unowned Operators, and displaying Operator names directly in the combat list — truly achieving "one click, all done"~
#### New Content Support
- [CN ONLY] **Arena Channel: Honeydew** entry (Use the same code for Green Grass City)
- **New Terminal interface** adaptation for global servers
#### Other Improvements
- Added detection for the black return button after auto-battle ends, making runs more robust
- UI and interaction polish — dark mode looks more natural
----
以下是详细内容:
## v5.24.2
## v5.16.5
### 新增 | New
* 适配 命运(AveMujica) 主题 (#13970) @weinibuliu
* SideStory「无忧梦呓」导航 (#13969) @SherkeyXD
* 勾选 「下次公告更新前不再显示」 勾选框时不需要滚到底才能关闭公告 @ABA2396
* Mac新增基建配置 @hguandl
* 特征匹配 (#10966) @status102
* 绿票、黄票、活动商店 (#12586) @Daydreamer114 @status102 @ABA2396
### 改进 | Improved
* 优化关卡验证逻辑,避免导入错误类型关卡时直接崩溃 @ABA2396
* 调整连战输出 @ABA2396
* 肉鸽不期而遇退出检测加个重试 @status102
### 修复 | Fix
* 肉鸽因模拟器卡顿偶现无法退出商店 @ABA2396
* OF-1 无法切换分队 @status102
* 蜜果城模拟器卡顿时可能无法返回主界面 @Windsland52
* 八幡海铃识别错误 @Saratoga-Official
* 选技能可能会点到技能范围 @ABA2396
### 其他 | Other
* 关卡小提示改用 Value @ABA2396
* 调整日志输出格式 @ABA2396
* 悖论模拟选技能改用固定位置,避免透明背景影响 @ABA2396
## v5.24.1
### 新增 | New
* 适配 悬想(界园肉鸽) 主题 (#13948) @weinibuliu
* 繁中服「視相」主題介面 (#13947) @momomochi987
* 悖论通关后自动取消勾选,遇到战斗失败的关卡时停止 (#13963) @ABA2396
### 改进 | Improved
* 日志记录增加 ClassName 输出debug 模式下属性切换新增反引号显示 @ABA2396
* 优化 Copilot 列表验证逻辑,提高性能 @ABA2396
### 修复 | Fix
* 自动编队后续追加自定干员失败 @status102
* 错误的关卡名可能导致验证崩溃 @ABA2396
* 公告重复点击时不会前置窗口 @ABA2396
* 战斗列表无法进入 1/2 星干员悖论 @ABA2396
* 悖论模拟战斗列表页尾干员错位 @ABA2396
* 空作业列表点开始崩溃 @status102
* 繁中服薩米肉鴿第五層名稱 (#13961) @momomochi987
* EN not picking up Trade Orders @Constrat
* IS5 EN StageRefresh not working, updated template @Constrat
* IS2 and IS3 not starting for EN @Constrat
* update Infrast templates for EN @Constrat
* 修复MaaCore asst.log文件句柄泄露 (#12639) @status102
* 修复了屎遇上手动覆盖文件的大聪明爆炸的问题 @ABA2396
* 凹开局干员直升精二选项显示时机错误 @ABA2396
* 连战次数乘号匹配失败 @status102
* store underfunded ocr full match @Daydreamer114
### 文档 | Docs
* 修正文档中的部分错误 (#13923) @lucienshawls
* 任务流color_scales注释优化 @status102
### 其他 | Other
* 将 「掉线时自动重连」 从 「运行设置」 移到 「刷理智设置」 中 @ABA2396
* 将 「自动肉鸽在战斗结束前延迟停止动作」 从 「运行设置」 移到 「肉鸽设置」 中 @ABA2396
* 繁中服「銀心湖列車」復刻活動導航 (#13945) @momomochi987
* 调整公告日志记录 @ABA2396
* 提取 isBuildOutputFolder @ABA2396
* 编译目录下不检查 dll @ABA2396
* 长草任务运行状态 (#13928) @status102
* 简化 Split @ABA2396
* OperatorType -> OperatorRole @status102
* JP ocr fix (#13938) @Manicsteiner
* i18n @Constrat @Manicsteiner
## v5.24.0
### 新增 | New
* 悖论模拟战斗列表通过职业找人 @ABA2396
* 悖论模拟战斗列表支持跳过未拥有的干员 @ABA2396
* 战斗列表悖论模拟关卡名转为干员名 @ABA2396
* 支持一键悖论模拟 (#13893) @status102 @Constrat @Burnside999 @momomochi987 @HX3N @Manicsteiner @ABA2396
* 争锋频道:蜜果城 @ABA2396
* mac 支持蜜果城 @ABA2396
* 调整战斗列表提示描述 @ABA2396
* 远程通知添加 `[MAA]` 前缀 @ABA2396
* 加个启动提醒 @ABA2396
* 在启动时检测额外的 DLL 文件 (#13850) @Rbqwow @ABA2396
* 自动战斗关卡结束后增加识别使用黑色返回按钮的检测 @status102
* 更新源为海外源时隐藏 Mirror酱 CDK 输入框 @ABA2396
### 改进 | Improved
* 覆盖 ThirdlyTextBrush优化深色模式下的显示效果 @ABA2396
* 任务 baseTask @status102
* 重构自动战斗战斗列表 (#13852) @status102
* 更新 CsWin32 @ABA2396
* ToastNotification 重构 @ABA2396
* 向战斗队列中添加 SSS 作业时追加错误输出 @status102
* limit codeql run only to source code (#13802) @Constrat
### 修复 | Fix
* 悖论模拟单文件无法使用 @ABA2396
* 关卡名下划线被解释成 CheckBox 访问键 @ABA2396
* 勾八导航乱写 @ABA2396
* 自动战斗界面 Idle setter 限制 @status102
* 自动战斗-战斗列表使用错误的作业战斗 @status102
* 信用购物有时候点不掉危机合约支援界面 @ABA2396
* ServerChan 未使用通用 httpService @ABA2396
* 错误清除 _tasksStatus 的时机 @ABA2396
* 肉鸽入口等待 ocr 识别错误 @ABA2396
* 界园肉鸽商店钱包余额ocr roi @status102
* 自动战斗-战斗列表`突袭`提示显示在运行期显示效果 @status102
* 不再点击停止任务时移除存储的 TaskId @status102
* 繁中服薩米肉鴿第四層名稱 (#13846) @momomochi987
* 肉鸽投资存款不变重试 20 次退出 @status102
* required version 显示错误 @ABA2396
* 会客室换班失败(如选人过程中弹出线索交流完成)时重开任务 @ABA2396
* 肉鸽开局招募在无开局干员时, 无法识别两招募的左侧位 @status102
* 千古鸭帝进战斗 @Saratoga-Official
* 日服的萨卡兹第五层怎么全 jb 改成 exit 了 @ABA2396
* 自动战斗干员编队状态; 修复编队中干员属性未达标时反复报错; 缺少干员输出时, 干员组内干员打平输出 (#13795) @status102
* 修正生息演算中 "丰饶灌木林" 的 OCR 识别 (#13825) @Alan-Charred
* 资源更新文件处理 @hguandl
* 萨卡兹肉鸽因动画延时偶发无法领取去伪存真合成物品 @ABA2396
* 萨米投资进二层会卡在预见密文板 @ABA2396
* CrownSlayer -> Crownslayer for EN @Constrat
* RoguelikeDialogSkip for EN @Constrat
* BattleQuickFormationExpandRole text ocr @Constrat
* OfficeMini template for EN @Constrat
* OfficeMini template for EN @Constrat
* ROI and text for EA YostarEN @Constrat
* YostarEN text render template changes @Constrat
* var type @status102
* YostarKR EA navigation @HX3N
* filters @ABA2396
### 其他 | Other
* 整合枚举类 OperProfession 和 Role (#13914) @soundofautumn
* 悖论模拟使用多任务流程 @status102
* 移除MaaCore不再支持的自动战斗作业代码解析 @status102
* 删掉 core 的联网功能 @ABA2396
* core 删除 cpr @ABA2396
* dll 检测排除带 maa 的 dll @ABA2396
* 自动战斗模组错误本地化 & 移除多余的行末空格 (#13800) @soundofautumn @Constrat @HX3N
* 调整小游戏内容顺序 @ABA2396
* 修改 RA 和肉鸽的进入终端等待时间 @ABA2396
* 调整萨卡兹,界园的古米精二优先度 @Saratoga-Official
* 修改备份文件写入时间 @ABA2396
* 关机/休眠/睡眠 统一调用 PowerManagement @ABA2396
* 调整 GetModuleFileName 判断 @ABA2396
* 移除未使用的 container @ABA2396
* mumu 使用 7555 端口时禁用 Index 检测,添加日志警告 @ABA2396
* file header @status102
* 自动编队助战的确实干员读取 @status102
* 加点肉鸽事件 fallback 前延迟,可能减轻点网络波动影响 @ABA2396
* 自动战斗不再使用 `need_navigate` 字段作为导航启用开关, 而是直接使用 `navigate_name` 字段 @status102
* 调整技能截图判断 @ABA2396
* YostarEN updated main stage navigation (#13906) @Constrat
* Give new line for English downloading from @Constrat
* YostarJP remove old navigation (#13905) @Manicsteiner
* YostarJP/KR new main stage navigation and ocr fix @Manicsteiner @HX3N
* A single-line comment within C# code is not preceded by a blank line. @ABA2396
* A C# partial element is missing a documentation header. @ABA2396
* An item within a C# enumeration is missing an Xml documentation header. @ABA2396
* A C# method, constructor, delegate or indexer element is missing documentation for one or more of its parameters. @ABA2396
* The XML header documentation for a C# element is missing a tag. @ABA2396
* Copyright 2025 @ABA2396
* Update localization strings for Mini Game section @AnnAngela
* yellow ticket items @Daydreamer114
* ocrTask text @status102
* Store@UnderfundedOCR @Daydreamer114
* 再铲一屎 @status102
* cache 移动逻辑 @ABA2396
* ubuntu unused @status102
* 铲屎 @status102
* 指定类型 @status102
* store loading @Daydreamer114
* Revert "feat: 在肉鸽招募中增加m3作为群奶 (#12353)" @Saratoga-Official
* 简化代码 @ABA2396
* 提示补全 @status102
* NumberReplace @status102
* 再次调整官网细节 @MistEO
* 调整官网标题 @MistEO
* Revert "fix: github change string to int (#12574)" @Daydreamer114
* 绿票、黄票、活动商店-国际服适配 (#12674) @Daydreamer114
* mark @status102
* 调整 UI 与 Core 版本不一致的解决方案提示 @ABA2396
* 点击任意职业回正列表 @ABA2396
* 基建先进行技能识别并返回列表首位,再清空选择 @ABA2396

View File

@@ -1,77 +1,70 @@
cmake_minimum_required(VERSION 3.28)
project(MAA)
cmake_minimum_required(VERSION 3.21)
project(MaaAssistantArknights)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
endif ()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
option(BUILD_WPF_GUI "build MaaWpfGui" ${WIN32})
option(BUILD_DEBUG_DEMO "build debug demo" OFF)
option(BUILD_TEST "build a demo" OFF)
option(BUILD_XCFRAMEWORK "build xcframework for macOS app" OFF)
option(BUILD_UNIVERSAL "build both arm64 and x86_64 on macOS" OFF)
option(INSTALL_PYTHON "install python ffi" OFF)
option(INSTALL_RESOURCE "install resource" OFF)
option(INSTALL_DEVEL "install development files" OFF)
option(INSTALL_FLATTEN "do not use bin lib include directory" ON)
option(INSTALL_THIRD_LIBS "install third party libraries" ON)
option(USE_MAADEPS "use third-party libraries built by MaaDeps" ON)
option(USE_RANGE_V3 "use range-v3" OFF)
option(WITH_EMULATOR_EXTRAS "build with emulator extras" ${WIN32})
option(BUILD_SMOKE_TEST "build smoke_test" OFF)
option(BUILD_RES_UPDATER "build ResourceUpdater" OFF)
option(WITH_THRIFT "build with thrift" OFF)
option(WITH_ASST_DEBUG "build with ASST_DEBUG defined" OFF)
include(${PROJECT_SOURCE_DIR}/MaaDeps/maadeps.cmake)
include(${PROJECT_SOURCE_DIR}/cmake/config.cmake)
include(${PROJECT_SOURCE_DIR}/cmake/utils.cmake)
include(${PROJECT_SOURCE_DIR}/cmake/version.cmake)
include(${PROJECT_SOURCE_DIR}/cmake/thrift-gen.cmake)
add_library(HeaderOnlyLibraries INTERFACE)
target_include_directories(HeaderOnlyLibraries INTERFACE 3rdparty/include 3rdparty/EmulatorExtras)
if(USE_MAADEPS)
include(${PROJECT_SOURCE_DIR}/MaaDeps/maadeps.cmake)
endif()
file(GLOB_RECURSE maa_src src/MaaCore/*.h src/MaaCore/*.hpp src/MaaCore/*.cpp)
add_library(header_only_libraries INTERFACE)
target_include_directories(header_only_libraries INTERFACE 3rdparty/include 3rdparty/EmulatorExtras)
file(GLOB_RECURSE maa_src src/MaaCore/*.cpp)
add_library(MaaCore SHARED ${maa_src})
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs)
find_package(Boost REQUIRED CONFIG COMPONENTS system)
find_package(ZLIB REQUIRED)
find_package(fastdeploy_ppocr REQUIRED)
find_package(ONNXRuntime REQUIRED)
if (MSVC)
target_compile_options(MaaCore PRIVATE "/utf-8")
target_compile_options(MaaCore PRIVATE "/MP")
target_compile_options(MaaCore PRIVATE "/W4;/WX")
target_compile_options(MaaCore PRIVATE "/wd4127") # conditional expression is constant
target_compile_options(MaaCore PRIVATE "/Wv:19.35.32217") # disable warning introduced after this version
target_link_libraries(MaaCore HeaderOnlyLibraries ${OpenCV_LIBS} fastdeploy_ppocr ONNXRuntime::ONNXRuntime ZLIB::ZLIB Boost::system)
if(WIN32)
target_link_libraries(MaaCore ws2_32)
endif()
if(LINUX)
target_link_libraries(MaaCore pthread)
endif()
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${maa_src})
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
else ()
target_compile_options(MaaCore PRIVATE "-Wall;-Wextra;-Wpedantic")
# LLVM clang 16 will failed with `error: no member named 'join' in namespace 'std::ranges::views'`, but Apple clang 16 won't
# value defined in https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
if ((CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16)
OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17))
target_compile_options(MaaCore PRIVATE "-fexperimental-library")
endif ()
endif ()
if (WIN32)
#注意相比VS版本缺少了 -D_CONSOLE -D_WINDLL 两项
target_compile_definitions(MaaCore PRIVATE ASST_DLL_EXPORTS _UNICODE UNICODE)
endif ()
target_include_directories(MaaCore PUBLIC include PRIVATE src/MaaCore)
set(MaaCore_PUBLIC_HEADERS include/AsstCaller.h include/AsstPort.h)
target_sources(MaaCore PUBLIC ${MaaCore_PUBLIC_HEADERS})
set_target_properties(MaaCore PROPERTIES PUBLIC_HEADER "${MaaCore_PUBLIC_HEADERS}")
if(WIN32)
add_custom_command(
TARGET MaaCore
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different
"${PROJECT_SOURCE_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/$<$<CONFIG:Debug>:msvc-debug/>"
$<TARGET_FILE_DIR:MaaCore>
COMMAND_EXPAND_LISTS)
endif()
if (BUILD_WPF_GUI)
include_external_msproject(MaaWpfGui ${PROJECT_SOURCE_DIR}/src/MaaWpfGui/MaaWpfGui.csproj)
add_dependencies(MaaWpfGui MaaCore)
endif()
set_target_properties(MaaCore PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
PUBLIC_HEADER "${MaaCore_PUBLIC_HEADERS}"
)
if(APPLE)
set_target_properties(MaaCore PROPERTIES INSTALL_RPATH "@loader_path/")
@@ -79,19 +72,90 @@ elseif(UNIX)
set_target_properties(MaaCore PROPERTIES INSTALL_RPATH "$ORIGIN/")
endif()
if (BUILD_TEST)
add_executable(test src/Cpp/main.cpp)
set_target_properties(test PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
)
target_link_libraries(test MaaCore)
endif (BUILD_TEST)
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs videoio features2d)
find_package(OpenCV QUIET COMPONENTS xfeatures2d)
find_package(ZLIB REQUIRED)
find_package(cpr CONFIG REQUIRED)
list(APPEND maa_libs ${OpenCV_LIBS} ZLIB::ZLIB cpr::cpr header_only_libraries)
if(USE_MAADEPS)
find_package(asio REQUIRED)
list(APPEND maa_libs asio::asio)
endif()
find_package(onnxruntime CONFIG REQUIRED) # provided by onnxruntime>=1.16
list(APPEND maa_libs onnxruntime::onnxruntime)
if(DEFINED fastdeploy_SOURCE_DIR)
# TODO: FetchContent github.com/MaaAssistantArknights/FastDeploy
if(NOT DEFINED fastdeploy_BINARY_DIR)
set(fastdeploy_BINARY_DIR ${CMAKE_BINARY_DIR}/fastdeploy)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${fastdeploy_SOURCE_DIR} ${fastdeploy_BINARY_DIR} EXCLUDE_FROM_ALL SYSTEM)
if(NOT DEFINED fastdeploy_INCLUDE_DIRS)
set(fastdeploy_INCLUDE_DIRS ${fastdeploy_SOURCE_DIR})
endif()
target_include_directories(MaaCore SYSTEM PRIVATE ${fastdeploy_INCLUDE_DIRS})
get_target_property(fastdeploy_type fastdeploy_ppocr TYPE)
if(fastdeploy_type STREQUAL "SHARED_LIBRARY")
install(TARGETS fastdeploy_ppocr)
endif()
else()
find_package(fastdeploy_ppocr REQUIRED)
endif()
list(APPEND maa_libs fastdeploy_ppocr)
target_link_libraries(MaaCore ${maa_libs})
if(WITH_EMULATOR_EXTRAS AND NOT EXISTS ${PROJECT_SOURCE_DIR}/3rdparty/EmulatorExtras/Mumu)
message(WARNING "EmulatorExtras not found, please run `git submodule update --init 3rdparty/EmulatorExtras`")
set(WITH_EMULATOR_EXTRAS OFF)
endif()
target_compile_definitions(MaaCore PRIVATE ASST_WITH_EMULATOR_EXTRAS=$<BOOL:${WITH_EMULATOR_EXTRAS}>)
if(WITH_THRIFT)
find_package(Thrift CONFIG REQUIRED)
add_subdirectory(src/MaaThriftController)
target_link_libraries(MaaCore MaaThriftController)
endif(WITH_THRIFT)
if (WITH_ASST_DEBUG)
target_compile_definitions(MaaCore PRIVATE ASST_DEBUG)
endif ()
if(WIN32)
target_link_libraries(MaaCore ws2_32)
endif()
if (USE_RANGE_V3)
target_compile_definitions(MaaCore PRIVATE ASST_USE_RANGES_RANGE_V3)
find_package(range-v3 REQUIRED)
target_link_libraries(MaaCore range-v3::range-v3)
endif ()
if(INSTALL_DEVEL)
set(MaaCore_install_extra_args PUBLIC_HEADER DESTINATION devel/include ARCHIVE DESTINATION devel/lib)
endif()
if(INSTALL_FLATTEN)
set(MaaCore_install_flatten_args RUNTIME DESTINATION . LIBRARY DESTINATION . PUBLIC_HEADER DESTINATION .)
endif()
install(TARGETS MaaCore ${MaaCore_install_flatten_args})
install(TARGETS MaaCore ${MaaCore_install_flatten_args} ${MaaCore_install_extra_args})
maadeps_install(.)
if(INSTALL_THIRD_LIBS AND USE_MAADEPS)
maadeps_install()
endif()
if (INSTALL_PYTHON)
install(DIRECTORY src/Python DESTINATION .)
@@ -100,50 +164,32 @@ if (INSTALL_RESOURCE)
install(DIRECTORY resource DESTINATION .)
endif (INSTALL_RESOURCE)
if (BUILD_DEBUG_DEMO)
add_executable(debug_demo src/Cpp/main.cpp)
if(MSVC)
target_compile_options(debug_demo PRIVATE "/WX-")
else()
target_compile_options(debug_demo PRIVATE "-Wno-error")
endif()
target_link_libraries(debug_demo MaaCore)
add_dependencies(debug_demo MaaCore)
# install(TARGETS debug_demo ${MaaCore_install_flatten_args})
endif (BUILD_DEBUG_DEMO)
if (BUILD_SMOKE_TEST)
add_executable(smoke_test src/Cpp/main.cpp)
if(MSVC)
target_compile_options(smoke_test PRIVATE "/WX-")
else()
target_compile_options(smoke_test PRIVATE "-Wno-error")
endif()
target_compile_definitions(smoke_test PRIVATE SMOKE_TESTING)
target_link_libraries(smoke_test MaaCore)
add_dependencies(smoke_test MaaCore)
install(TARGETS smoke_test ${MaaCore_install_flatten_args})
endif (BUILD_SMOKE_TEST)
if (BUILD_RES_UPDATER)
add_executable(ResourceUpdater tools/ResourceUpdater/main.cpp)
target_include_directories(ResourceUpdater PUBLIC include PRIVATE src/MaaCore) # For Utils/Time.hpp
target_link_libraries(ResourceUpdater HeaderOnlyLibraries ${OpenCV_LIBS})
if(LINUX)
target_link_libraries(ResourceUpdater pthread)
endif()
install(TARGETS ResourceUpdater DESTINATION . COMPONENT ResourceUpdater)
# Copy from maadeps_install, adding component
if(MSVC)
install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/$<$<CONFIG:Debug>:msvc-debug/>" DESTINATION . USE_SOURCE_PERMISSIONS COMPONENT ResourceUpdater)
else()
install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/" DESTINATION . USE_SOURCE_PERMISSIONS COMPONENT ResourceUpdater)
endif()
endif (BUILD_RES_UPDATER)
if (APPLE)
include(${PROJECT_SOURCE_DIR}/cmake/macos.cmake)
endif (APPLE)
# define MAA_VERSION from git
if (NOT DEFINED MAA_VERSION)
find_package(Git)
endif ()
if (NOT DEFINED MAA_VERSION AND GIT_FOUND)
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE result
OUTPUT_VARIABLE output
ERROR_VARIABLE err
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (result EQUAL 0)
set(MAA_VERSION "${output}")
else ()
message(WARNING "git rev-parse returning ${result}, output:\n${err}")
endif ()
endif ()
if (NOT MAA_VERSION)
set(MAA_VERSION "DEBUG VERSION")
endif ()
message(STATUS "MAA_VERSION=${MAA_VERSION}")
add_compile_definitions(MAA_VERSION="${MAA_VERSION}")

View File

@@ -20,61 +20,58 @@ openfiles >nul 2>&1
if %errorlevel% neq 0 (
echo %YELLOW%正在获取管理员权限...%RESET%
echo %YELLOW%Obtaining administrator privileges...%RESET%
powershell -Command "Start-Process cmd.exe -ArgumentList '/c %~f0' -Verb RunAs"
powershell -Command "Start-Process cmd.exe -ArgumentList '/c %~dpnx0' -Verb RunAs"
exit /b
)
echo.
echo %BLUE%====================================================================================================%RESET%
echo %BLUE%========================================%RESET%
echo %BOLD%%CYAN%正在安装 Microsoft Visual C++ Redistributable%RESET%
echo %BOLD%%CYAN%Installing Microsoft Visual C++ Redistributable%RESET%
echo.
echo %YELLOW%如果是第一次使用 winget可能会提示接受协议请输入 Y 并按回车继续%RESET%
echo %YELLOW%If this is your first time using winget, you may be prompted to accept the terms. %RESET%
echo %YELLOW%Please enter Y and press Enter to continue.%RESET%
echo %BLUE%========================================%RESET%
echo.
winget install "Microsoft.VCRedist.2015+.x64" --override "/repair /passive /norestart" --uninstall-previous --accept-package-agreements --force
if %errorlevel% neq 0 (
echo.
echo %BOLD%%RED%错误: Microsoft.VCRedist.2015+.x64 安装失败%RESET%
echo %BOLD%%RED%Error: Microsoft.VCRedist.2015+.x64 installation failed%RESET%
set "ErrorOccurred=1"
)
echo %BLUE%====================================================================================================%RESET%
echo.
echo %BLUE%====================================================================================================%RESET%
echo %BLUE%========================================%RESET%
echo %BOLD%%CYAN%正在安装 .NET Desktop Runtime 8.0%RESET%
echo %BOLD%%CYAN%Installing .NET Desktop Runtime 8.0%RESET%
echo %BLUE%========================================%RESET%
echo.
winget install "Microsoft.DotNet.DesktopRuntime.8" --override "/repair /passive /norestart" --uninstall-previous --accept-package-agreements --force
if %errorlevel% neq 0 (
echo.
echo %BOLD%%RED%错误: Microsoft.DotNet.DesktopRuntime.8 安装失败%RESET%
echo %BOLD%%RED%Error: Microsoft.DotNet.DesktopRuntime.8 installation failed%RESET%
set "ErrorOccurred=1"
)
echo %BLUE%====================================================================================================%RESET%
echo.
if %ErrorOccurred% equ 0 (
echo %BOLD%%GREEN%运行库修复完成,请重启电脑后再次尝试运行 MAA。%RESET%
echo %BOLD%%GREEN%The runtime library repair is complete. Please restart your computer and try running MAA again.%RESET%
) else (
echo %RED%====================================================================================================%RESET%
echo %RED%========================================%RESET%
echo %BOLD%%RED%运行库修复过程中出现错误%RESET%
echo %BOLD%%RED%Errors occurred during runtime library repair%RESET%
echo.
echo %YELLOW%如果提示%RESET% %WHITE%'winget' is not...%RESET% %YELLOW%说明您的电脑版本太老了,没有自带 winget%RESET%
echo %YELLOW%If the prompt shows%RESET% %WHITE%'winget' is not...%RESET% %YELLOW%it means your system is too old and don't include winget by default.%RESET%
echo.
echo %YELLOW%您可以手动将以下两个链接复制到浏览器中打开,下载并安装所需组件。如果安装成功,无需再次运行本依赖库安装脚本。%RESET%
echo %YELLOW%You can manually copy the following two links into your browser to download and install the required components.%RESET%
echo %YELLOW%If the installation is successful, you don't need to run this dependency installation script again.%RESET%
echo %YELLOW%您可以尝试手动下载并安装以下组件:%RESET%
echo %YELLOW%You can try to manually download and install the following components:%RESET%
echo.
echo %WHITE%Microsoft Visual C++ Redistributable:%RESET%
echo %CYAN%https://aka.ms/vs/17/release/vc_redist.x64.exe%RESET%
echo.
echo %WHITE%.NET Desktop Runtime 8.0:%RESET%
echo %CYAN%https://aka.ms/dotnet/8.0/windowsdesktop-runtime-win-x64.exe%RESET%
echo %RED%====================================================================================================%RESET%
echo %RED%========================================%RESET%
)
pause
pause

15
MAA.DotSettings Normal file
View File

@@ -0,0 +1,15 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Arknights/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bilibili/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Infrast/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=oper/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=opers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pallas/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pormpt/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Rougelike/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=templ/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=thres/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Todays/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=txwy/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=vuvm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=XYAZ/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

106
MAA.sln Normal file
View File

@@ -0,0 +1,106 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaaWpfGui", "src\MaaWpfGui\MaaWpfGui.csproj", "{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC} = {F860C043-4D86-41B6-A97E-4A75C9A6C4EC}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MaaCore", "src\MaaCore\MaaCore.vcxproj", "{362D1E30-F5AE-4279-9985-65C27B3BA300}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MaaThriftController", "src\MaaThriftController\MaaThriftController.vcxproj", "{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{11F02235-5785-408B-9651-8A4B41FF36F4}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SyncRes", "src\SyncRes\SyncRes.csproj", "{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sample", "src\Cpp\MaaSample.vcxproj", "{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC} = {F860C043-4D86-41B6-A97E-4A75C9A6C4EC}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
RelWithDebInfo|ARM64 = RelWithDebInfo|ARM64
RelWithDebInfo|x64 = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|ARM64.ActiveCfg = Debug|ARM64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|ARM64.Build.0 = Debug|ARM64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|x64.ActiveCfg = Debug|x64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|x64.Build.0 = Debug|x64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|ARM64.ActiveCfg = Release|ARM64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|ARM64.Build.0 = Release|ARM64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.ActiveCfg = Release|x64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.Build.0 = Release|x64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|ARM64.ActiveCfg = Debug|ARM64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|ARM64.Build.0 = Debug|ARM64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|x64.ActiveCfg = Debug|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|x64.Build.0 = Debug|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|ARM64.ActiveCfg = Release|ARM64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|ARM64.Build.0 = Release|ARM64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.ActiveCfg = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.Build.0 = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Debug|ARM64.Build.0 = Debug|ARM64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Debug|x64.ActiveCfg = Debug|x64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Debug|x64.Build.0 = Debug|x64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Release|ARM64.ActiveCfg = Release|ARM64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Release|ARM64.Build.0 = Release|ARM64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Release|x64.ActiveCfg = Release|x64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.Release|x64.Build.0 = Release|x64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{8238EDB1-19BF-4E3B-AF5B-016120D59D7B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Debug|ARM64.Build.0 = Debug|ARM64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Debug|x64.ActiveCfg = Debug|x64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Debug|x64.Build.0 = Debug|x64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Release|ARM64.ActiveCfg = Release|ARM64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Release|ARM64.Build.0 = Release|ARM64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Release|x64.ActiveCfg = Release|x64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.Release|x64.Build.0 = Release|x64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{F860C043-4D86-41B6-A97E-4A75C9A6C4EC}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Debug|ARM64.ActiveCfg = Debug|ARM64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Debug|ARM64.Build.0 = Debug|ARM64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Debug|x64.ActiveCfg = Debug|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Debug|x64.Build.0 = Debug|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|ARM64.ActiveCfg = Release|ARM64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|ARM64.Build.0 = Release|ARM64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x64.ActiveCfg = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x64.Build.0 = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4F2C0E4B-4FE9-47C6-A878-6BD2FAD8B9B2}
EndGlobalSection
EndGlobal

170
MAA.sln.DotSettings Normal file
View File

@@ -0,0 +1,170 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EN/@EntryIndexedValue">EN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KR/@EntryIndexedValue">KR</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JP/@EntryIndexedValue">JP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GUI/@EntryIndexedValue">GUI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SWMINIMIZE/@EntryIndexedValue">SWMINIMIZE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=AP/@EntryIndexedValue">AP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=AP_002D/@EntryIndexedValue">AP-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=CA/@EntryIndexedValue">CA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=CA_002D/@EntryIndexedValue">CA-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=CE/@EntryIndexedValue">CE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=CE_002D/@EntryIndexedValue">CE-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=EN/@EntryIndexedValue">EN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=IS/@EntryIndexedValue">IS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=JP/@EntryIndexedValue">JP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=KR/@EntryIndexedValue">KR</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=LD/@EntryIndexedValue">LD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=LS/@EntryIndexedValue">LS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=LS_002D/@EntryIndexedValue">LS-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DA/@EntryIndexedValue">PR-A</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DA_002D/@EntryIndexedValue">PR-A-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DB/@EntryIndexedValue">PR-B</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DB_002D/@EntryIndexedValue">PR-B-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DC/@EntryIndexedValue">PR-C</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DC_002D/@EntryIndexedValue">PR-C-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DD/@EntryIndexedValue">PR-D</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=PR_002DD_002D/@EntryIndexedValue">PR-D-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=SK/@EntryIndexedValue">SK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=SK_002D/@EntryIndexedValue">SK-</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=SSS/@EntryIndexedValue">SSS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=WSA/@EntryIndexedValue">WSA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=XYAZ/@EntryIndexedValue">XYAZ</s:String>
<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=Github/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=_4E00_9375_8F2A/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=_591C_95F4_6A21_5F0F/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acast/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acfend/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acguad/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acpion/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acspec/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acsupo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=advapi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aero/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Affero/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=aguard/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=amedic/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=amiya/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=apionr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=arget/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Arknights/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=arkplanner/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=asnipe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=autofill/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bilibili/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bluestacks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=bsconsole/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ccast/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cdfend/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cguard/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Chayn/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Chyan/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cmedic/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Collapsal/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cpione/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=csnipe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cspec/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=csuppo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ctrler/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=desp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dnplayer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Ehem/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=esource/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Eyjafjalla/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Favourite/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=filetime/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=findstr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FLASHW/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FLASHWINFO/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=foldartal/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Foldartals/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=framerate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=furni/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Gacha/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Gavial/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Grandet/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Hotkey/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hwnd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Infrast/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Inited/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=iter/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=jsend/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ldconsole/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ldplayer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=LD_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=leidian/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lolicon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=lpwndpl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ls_005B_0022sub/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=luestacks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=maatouch/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=MAA_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=memuc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Minitouch/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mirrorc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mirrorchyan/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mizuki/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mumu/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nemu/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Netease/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=netstat/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nonfriend/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=notstationed/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=objstr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=oper/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=opers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Originite/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Originium/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=originiums/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Orundum/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Orundums/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=o_FF9Fv_FF9F/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pallas/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pidl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pormpt/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=powrprof/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ppidl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pwfi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=qmsg/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Raidian/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rcast/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rdfend/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=removelist/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rguard/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rmean/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rmedic/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Roguelike/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rsnipe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sami/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sarkaz/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Screencap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=sctp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=serilog/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Showminimized/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Shownormal/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skland/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=specialaccess/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=spid/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SSS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=STGM/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stormeye/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=strlen/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stylet/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=subtask/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Suppressions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Surtr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SWMINIMIZE/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=taskchain/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Todays/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=txwy/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ucrtbase/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=vmonitor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhook/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=XYAZ/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Yahei/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=yituliu/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Yostar/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0020_0020_0020wp_002ELength_0020/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0020_003D_0020stri/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -108,8 +108,12 @@ MAA 支持命令行界面CLI操作支持 LinuxmacOS 和 Windows
### 多语言 (i18n)
MAA 支持多国语言,并使用 Weblate 进行本地化管理。如果您通晓多门语言,欢迎前往 [MAA Weblate](https://weblate.maa-org.net) 帮助我们进行翻译。
MAA 以中文(简体)为第一语言,翻译词条均以中文(简体)为准。
[![Weblate](https://weblate.maa-org.net/widget/maa/wpf-gui/multi-auto.svg)](https://weblate.maa-org.net/engage/maa/)
### 参与开发
#### Windows

7
build.cmd Normal file
View File

@@ -0,0 +1,7 @@
:; set -eo pipefail
:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
:; ${SCRIPT_DIR}/build.sh "$@"
:; exit $?
@ECHO OFF
powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*

69
build.ps1 Normal file
View File

@@ -0,0 +1,69 @@
[CmdletBinding()]
Param(
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$BuildArguments
)
Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
###########################################################################
# CONFIGURATION
###########################################################################
$BuildProjectFile = "$PSScriptRoot\tools\MaaBuilder\MaaBuilder.csproj"
$TempDirectory = "$PSScriptRoot\\.nuke\temp"
$DotNetGlobalFile = "$PSScriptRoot\\global.json"
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "Current"
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
$env:DOTNET_MULTILEVEL_LOOKUP = 0
###########################################################################
# EXECUTION
###########################################################################
function ExecSafe([scriptblock] $cmd) {
& $cmd
if ($LASTEXITCODE) { exit $LASTEXITCODE }
}
# If dotnet CLI is installed globally and it matches requested version, use for execution
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
$(dotnet --version) -and $LASTEXITCODE -eq 0) {
$env:DOTNET_EXE = (Get-Command "dotnet").Path
}
else {
# Download install script
$DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
# If global.json exists, load expected version
if (Test-Path $DotNetGlobalFile) {
$DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
$DotNetVersion = $DotNetGlobal.sdk.version
}
}
# Install by channel or version
$DotNetDirectory = "$TempDirectory\dotnet-win"
if (!(Test-Path variable:DotNetVersion)) {
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
} else {
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
}
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
}
Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }

62
build.sh Normal file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/env bash
bash --version 2>&1 | head -n 1
set -eo pipefail
SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
###########################################################################
# CONFIGURATION
###########################################################################
BUILD_PROJECT_FILE="$SCRIPT_DIR/tools/MaaBuilder/MaaBuilder.csproj"
TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
DOTNET_CHANNEL="Current"
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
export DOTNET_MULTILEVEL_LOOKUP=0
###########################################################################
# EXECUTION
###########################################################################
function FirstJsonValue {
perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
}
# If dotnet CLI is installed globally and it matches requested version, use for execution
if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
export DOTNET_EXE="$(command -v dotnet)"
else
# Download install script
DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
mkdir -p "$TEMP_DIRECTORY"
curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
chmod +x "$DOTNET_INSTALL_FILE"
# If global.json exists, load expected version
if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
if [[ "$DOTNET_VERSION" == "" ]]; then
unset DOTNET_VERSION
fi
fi
# Install by channel or version
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
if [[ -z ${DOTNET_VERSION+x} ]]; then
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
else
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
fi
export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
fi
echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"

View File

@@ -1,83 +0,0 @@
set(debug_comp_defs "_DEBUG;ASST_DEBUG")
add_compile_definitions("$<$<CONFIG:Debug>:${debug_comp_defs}>")
if(APPLE)
set(CMAKE_INSTALL_RPATH "@loader_path;@executable_path")
set(CMAKE_BUILD_RPATH "@loader_path;@executable_path")
elseif(UNIX)
set(CMAKE_INSTALL_RPATH "$ORIGIN")
set(CMAKE_BUILD_RPATH "$ORIGIN")
endif()
if(MSVC)
add_compile_options("/utf-8")
add_compile_options("/MP")
add_compile_options("/W4;/WX;/Gy;/permissive-;/sdl")
add_compile_options("/wd4127") # conditional expression is constant
add_compile_options("/wd4251") # export dll with templates
add_compile_options("/DWINVER=0x0A00")
add_compile_options("/D_WIN32_WINNT=0x0A00")
# https://github.com/actions/runner-images/issues/10004 https://github.com/microsoft/STL/releases/tag/vs-2022-17.10
add_compile_definitions("_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR")
set(release_link_options "/OPT:REF;/OPT:ICF")
add_link_options("$<$<CONFIG:Release>:${release_link_options}>")
SET(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO "RelWithDebInfo;Release;")
SET(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL "MinSizeRel;Release;")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
else()
add_compile_options("-Wall;-Werror;-Wextra;-Wpedantic;-Wno-missing-field-initializers")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13)
add_compile_options("-Wno-restrict")
endif()
endif()
if(LINUX)
function(copy_and_add_rpath_library LIBNAME)
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=${LIBNAME}.so.1 -target ${CMAKE_CXX_COMPILER_TARGET} --sysroot=${CMAKE_SYSROOT}
OUTPUT_VARIABLE LIB_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if("${LIB_PATH}" STREQUAL "${LIBNAME}.so.1}")
message(FATAL_ERROR "Could not locate ${LIBNAME}.so.1 using compiler")
endif()
file(READ_SYMLINK "${LIB_PATH}" LINK_TARGET)
if(NOT LINK_TARGET)
set(LIB_PATH_REAL "${LIB_PATH}")
elseif(NOT IS_ABSOLUTE "${LINK_TARGET}")
get_filename_component(LIB_PATH_DIR "${LIB_PATH}" DIRECTORY)
file(REAL_PATH "${LIB_PATH_DIR}/${LINK_TARGET}" LIB_PATH_REAL)
else()
set(LIB_PATH_REAL "${LINK_TARGET}")
endif()
if(NOT EXISTS "${LIB_PATH_REAL}")
message(FATAL_ERROR "File not found: ${LIB_PATH_REAL}")
endif()
message(STATUS "${LIBNAME}.so.1 path: ${LIB_PATH_REAL}")
install(FILES "${LIB_PATH_REAL}" DESTINATION . RENAME "${LIBNAME}.so.1")
get_filename_component(LIB_PATH_DIR "${LIB_PATH_REAL}" DIRECTORY)
list(APPEND CMAKE_BUILD_RPATH "${LIB_PATH_DIR}")
set(CMAKE_BUILD_RPATH "${CMAKE_BUILD_RPATH}" PARENT_SCOPE)
endfunction()
copy_and_add_rpath_library(libc++)
copy_and_add_rpath_library(libc++abi)
copy_and_add_rpath_library(libunwind)
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

View File

@@ -1,19 +0,0 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(XTOOLS_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../MaaDeps/x-tools/aarch64-linux-gnu)
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
set(CMAKE_C_COMPILER clang-20)
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-gnu)
set(CMAKE_CXX_COMPILER clang++-20)
set(CMAKE_ASM_COMPILER_TARGET aarch64-linux-gnu)
set(CMAKE_ASM_COMPILER clang-20)
set(CMAKE_SYSROOT ${XTOOLS_ROOT}/aarch64-linux-gnu/sysroot)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT} -fuse-ld=lld --gcc-toolchain=${XTOOLS_ROOT}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT} -fuse-ld=lld --gcc-toolchain=${XTOOLS_ROOT}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT} -fuse-ld=lld --gcc-toolchain=${XTOOLS_ROOT}")
set(CMAKE_LINKER_TYPE LLD)

View File

@@ -1,19 +0,0 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(XTOOLS_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../MaaDeps/x-tools/x86_64-linux-gnu)
set(CMAKE_C_COMPILER_TARGET x86_64-linux-gnu)
set(CMAKE_C_COMPILER clang-20)
set(CMAKE_CXX_COMPILER_TARGET x86_64-linux-gnu)
set(CMAKE_CXX_COMPILER clang++-20)
set(CMAKE_ASM_COMPILER_TARGET x86_64-linux-gnu)
set(CMAKE_ASM_COMPILER clang-20)
set(CMAKE_SYSROOT ${XTOOLS_ROOT}/x86_64-linux-gnu/sysroot)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT} -fuse-ld=lld --gcc-toolchain=${XTOOLS_ROOT}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT} -fuse-ld=lld --gcc-toolchain=${XTOOLS_ROOT}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIC -stdlib=libc++ --sysroot=${CMAKE_SYSROOT} -fuse-ld=lld --gcc-toolchain=${XTOOLS_ROOT}")
set(CMAKE_LINKER_TYPE LLD)

View File

@@ -1,41 +0,0 @@
find_path(ONNXRuntime_INCLUDE_DIR NAMES onnxruntime/onnxruntime_c_api.h)
find_library(ONNXRuntime_LIBRARY_IMP NAMES onnxruntime)
if (WIN32)
get_filename_component(ONNXRuntime_PATH_LIB ${ONNXRuntime_LIBRARY_IMP} DIRECTORY)
find_file(ONNXRuntime_LIBRARY NAMES onnxruntime_maa.dll PATHS "${ONNXRuntime_PATH_LIB}/../bin")
find_file(ONNXRuntime_LIBRARY_IMP_DEBUG NAMES onnxruntime.lib PATHS "${ONNXRuntime_PATH_LIB}/../debug/lib")
find_file(ONNXRuntime_LIBRARY_DEBUG NAMES onnxruntime_maa.dll PATHS "${ONNXRuntime_PATH_LIB}/../debug/bin")
else ()
set(ONNXRuntime_LIBRARY ${ONNXRuntime_LIBRARY_IMP})
endif (WIN32)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
ONNXRuntime
REQUIRED_VARS ONNXRuntime_LIBRARY_IMP ONNXRuntime_INCLUDE_DIR
)
if(ONNXRuntime_FOUND)
set(ONNXRuntime_INCLUDE_DIRS ${ONNXRuntime_INCLUDE_DIR})
if(NOT TARGET ONNXRuntime::ONNXRuntime)
add_library(ONNXRuntime::ONNXRuntime SHARED IMPORTED)
set_property(TARGET ONNXRuntime::ONNXRuntime APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
if (WIN32)
set_property(TARGET ONNXRuntime::ONNXRuntime APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(ONNXRuntime::ONNXRuntime PROPERTIES
IMPORTED_IMPLIB_RELEASE "${ONNXRuntime_LIBRARY_IMP}"
)
set_target_properties(ONNXRuntime::ONNXRuntime PROPERTIES
IMPORTED_IMPLIB_DEBUG "${ONNXRuntime_LIBRARY_IMP_DEBUG}"
IMPORTED_LOCATION_DEBUG "${ONNXRuntime_LIBRARY_DEBUG}"
)
endif (WIN32)
set_target_properties(ONNXRuntime::ONNXRuntime PROPERTIES
IMPORTED_LOCATION_RELEASE "${ONNXRuntime_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${ONNXRuntime_INCLUDE_DIR}"
)
endif()
endif()

54
cmake/opencv.cmake Normal file
View File

@@ -0,0 +1,54 @@
set(OPENCV_URL_PREFIX "https://github.com/MaaAssistantArknights/build-opencv/releases/download")
set(OPENCV_TAG "4.5.3")
set(COMPRESSED_SUFFIX ".tar.gz")
if(WIN32)
set(OPENCV_FILENAME "OpenCV-Windows")
set(OPENCV_CHECKSUM "bf736b243bbdaa020f139e4dfa1e4f15633f4ce7a8ad885524645e660de47a8b")
elseif(APPLE)
if (CURRENT_OSX_ARCH STREQUAL "arm64")
set(OPENCV_FILENAME "OpenCV-macOS-arm64")
set(OPENCV_CHECKSUM "31beb633c033dd4ee789ffa50911c29c9580860f9a91f334f03d8aa9c85e9700")
else()
set(OPENCV_FILENAME "OpenCV-macOS-x86_64")
set(OPENCV_CHECKSUM "249c5c97cc52257b68d35acf499b1cf1037f5e6f3b40752f82ad5abe7884bea9")
endif()
else(UNIX)
set(OPENCV_FILENAME "OpenCV-Linux")
set(OPENCV_CHECKSUM "edc4138456189c9e8bdf29114ad2be8ec152e8e31087d98e633f6cda59b141ea")
endif(WIN32)
set(OPENCV_URL ${OPENCV_URL_PREFIX}/${OPENCV_TAG}/${OPENCV_FILENAME}${COMPRESSED_SUFFIX})
if(OPENCV_DIRECTORY)
set(OpenCV_DIR ${OPENCV_DIRECTORY})
find_package(OpenCV REQUIRED PATHS ${OpenCV_DIR})
include_directories(${OpenCV_INCLUDE_DIRS})
list(APPEND DEPEND_LIBS ${OpenCV_LIBS})
else()
download_and_decompress(${OPENCV_URL}
${CMAKE_CURRENT_BINARY_DIR}/${OPENCV_FILENAME}${COMPRESSED_SUFFIX}
${OPENCV_CHECKSUM}
${THIRD_PARTY_PATH}/install/)
set(OPENCV_FILENAME opencv)
set(OpenCV_DIR ${THIRD_PARTY_PATH}/install/${OPENCV_FILENAME})
set(OPENCV_DIRECTORY ${OpenCV_DIR})
if (WIN32)
set(OpenCV_DIR ${OpenCV_DIR}/lib)
endif()
find_package(OpenCV REQUIRED PATHS ${OpenCV_DIR} NO_DEFAULT_PATH)
include_directories(${OpenCV_INCLUDE_DIRS})
list(APPEND DEPEND_LIBS ${OpenCV_LIBS})
endif(OPENCV_DIRECTORY)
if (INSTALL_THIRD_LIBS)
if (OpenCV_SHARED)
install(DIRECTORY ${OpenCV_INSTALL_PATH}/lib/
DESTINATION .
USE_SOURCE_PERMISSIONS PATTERN "cmake" EXCLUDE)
endif (OpenCV_SHARED)
endif (INSTALL_THIRD_LIBS)

44
cmake/thrift-gen.cmake Normal file
View File

@@ -0,0 +1,44 @@
macro(GENERATE_THRIFT_LIB LIB_NAME FILENAME OUTPUTDIR SOURCES)
file(MAKE_DIRECTORY ${OUTPUTDIR})
detect_host_triplet(HOST_TRIPLET)
if (CMAKE_CROSSCOMPILING)
if (CMAKE_HOST_WIN32)
set(_host_executable_suffix ".exe")
else()
set(_host_executable_suffix "")
endif()
else()
set(_host_executable_suffix ${CMAKE_EXECUTABLE_SUFFIX})
endif()
if(EXISTS ${PROJECT_SOURCE_DIR}/MaaDeps/vcpkg/installed/maa-${HOST_TRIPLET}/tools/thrift/thrift${_host_executable_suffix})
set(THRIFT_COMPILER ${PROJECT_SOURCE_DIR}/MaaDeps/vcpkg/installed/maa-${HOST_TRIPLET}/tools/thrift/thrift${_host_executable_suffix})
else()
find_program(THRIFT_COMPILER thrift)
endif()
if(NOT THRIFT_COMPILER)
message(FATAL_ERROR "Thrift compiler not found")
endif()
get_filename_component(THRIFT_IDL_NAME ${FILENAME} NAME_WE)
set(THRIFT_IDL_TARGET "${LIB_NAME}_${THRIFT_IDL_NAME}_idl")
set("${THRIFT_IDL_NAME}-gen-cpp"
${OUTPUTDIR}/${THRIFT_IDL_NAME}.cpp
${OUTPUTDIR}/${THRIFT_IDL_NAME}.h
${OUTPUTDIR}/${THRIFT_IDL_NAME}_types.cpp
${OUTPUTDIR}/${THRIFT_IDL_NAME}_types.h)
add_custom_command(OUTPUT ${${THRIFT_IDL_NAME}-gen-cpp}
DEPENDS ${FILENAME}
COMMAND ${THRIFT_COMPILER} --gen cpp:no_skeleton -out ${OUTPUTDIR} ${FILENAME}
VERBATIM)
add_custom_target(${THRIFT_IDL_TARGET} DEPENDS ${${THRIFT_IDL_NAME}-gen-cpp})
add_library(${LIB_NAME} STATIC ${${THRIFT_IDL_NAME}-gen-cpp})
add_dependencies(${LIB_NAME} ${THRIFT_IDL_TARGET})
set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${LIB_NAME} PUBLIC thrift::thrift)
target_include_directories(${LIB_NAME} PUBLIC ${OUTPUTDIR})
set(${SOURCES} ${${SOURCES}} ${GENERATED_SOURCES} PARENT_SCOPE)
endmacro(GENERATE_THRIFT_LIB)
if (WITH_THRIFT)
add_compile_definitions(WITH_THRIFT)
endif (WITH_THRIFT)

View File

@@ -1,46 +1,50 @@
function(download_and_decompress url filename sha256_checksum decompress_dir)
if(EXISTS ${filename})
file(SHA256 ${filename} CHECKSUM_VARIABLE)
endif()
if(NOT EXISTS ${filename} OR NOT CHECKSUM_VARIABLE STREQUAL sha256_checksum)
message("Downloading file from ${url} to ${filename} ...")
file(
DOWNLOAD ${url} "${filename}.tmp"
SHOW_PROGRESS
EXPECTED_HASH SHA256=${sha256_checksum})
file(RENAME "${filename}.tmp" ${filename})
endif()
if(NOT EXISTS ${decompress_dir})
file(MAKE_DIRECTORY ${decompress_dir})
endif()
message("Decompress file ${filename} ...")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xf ${filename} WORKING_DIRECTORY ${decompress_dir})
if(EXISTS ${filename})
file(SHA256 ${filename} CHECKSUM_VARIABLE)
endif()
if(NOT EXISTS ${filename} OR NOT CHECKSUM_VARIABLE STREQUAL sha256_checksum)
message("Downloading file from ${url} to ${filename} ...")
file(DOWNLOAD ${url} "${filename}.tmp" SHOW_PROGRESS EXPECTED_HASH SHA256=${sha256_checksum})
file(RENAME "${filename}.tmp" ${filename})
endif()
if(NOT EXISTS ${decompress_dir})
file(MAKE_DIRECTORY ${decompress_dir})
endif()
message("Decompress file ${filename} ...")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xf ${filename} WORKING_DIRECTORY ${decompress_dir})
endfunction()
function(get_osx_architecture)
if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
set(CURRENT_OSX_ARCH
"arm64"
PARENT_SCOPE)
elseif(CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64")
set(CURRENT_OSX_ARCH
"x86_64"
PARENT_SCOPE)
else()
set(CURRENT_OSX_ARCH
${CMAKE_HOST_SYSTEM_PROCESSOR}
PARENT_SCOPE)
endif()
if (CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
set(CURRENT_OSX_ARCH "arm64" PARENT_SCOPE)
elseif(CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64")
set(CURRENT_OSX_ARCH "x86_64" PARENT_SCOPE)
else()
set(CURRENT_OSX_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR} PARENT_SCOPE)
endif()
endfunction()
if(APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET 13.3) # for to_chars
get_osx_architecture()
endif(APPLE)
function(detect_host_triplet outvar)
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" host_triplet_system)
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" host_triplet_arch)
if(host_triplet_system STREQUAL "darwin")
set(host_triplet_system "osx")
endif()
message("host_triplet_system: ${host_triplet_system}")
message("host_triplet_arch: ${host_triplet_arch}")
if(host_triplet_arch MATCHES "(amd64|x86_64)")
set(host_triplet_arch "x64")
elseif(host_triplet_arch MATCHES "i[3456]86")
set(host_triplet_arch "x86")
elseif(host_triplet_arch MATCHES "(aarch64|armv8l|arm64)")
set(host_triplet_arch "arm64")
else()
message(FATAL_ERROR "Unrecognized CMAKE_HOST_SYSTEM_PROCESSOR: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()
set(${outvar} "${host_triplet_arch}-${host_triplet_system}" PARENT_SCOPE)
endfunction()
if(NOT DEFINED MAADEPS_TRIPLET)
detect_maadeps_triplet(MAADEPS_TRIPLET)
endif()
if (APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET 12.0)
get_osx_architecture()
endif (APPLE)

View File

@@ -1,27 +0,0 @@
# define MAA_HASH_VERSION from git
set(MAA_HASH_VERSION
"DEBUG_VERSION"
CACHE STRING "maa version")
if(MAA_HASH_VERSION STREQUAL "DEBUG_VERSION")
find_package(Git)
endif()
if(MAA_HASH_VERSION STREQUAL "DEBUG_VERSION" AND GIT_FOUND)
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE result
OUTPUT_VARIABLE output
ERROR_VARIABLE err
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(result EQUAL 0)
set(MAA_HASH_VERSION "${output}")
else()
message(WARNING "git rev-parse returning ${result}, output:\n${err}")
endif()
endif()
message(STATUS "MAA_HASH_VERSION=${MAA_HASH_VERSION}")
add_compile_definitions(MAA_VERSION="${MAA_HASH_VERSION}")

View File

@@ -224,38 +224,3 @@ MD052: true
MD053:
# Ignored definitions
ignored_definitions: ["//"]
# MD054/link-image-style - Link and image style
MD054:
# Allow autolinks
autolink: true
# Allow collapsed reference links and images
collapsed: true
# Allow full reference links and images
full: true
# Allow inline links and images
inline: true
# Allow shortcut reference links and images
shortcut: true
# Allow URLs as inline links
url_inline: true
# MD055/table-pipe-style - Table pipe style
MD055:
# Table pipe style
style: "consistent"
# MD056/table-column-count - Table column count
MD056: true
# MD057 - Table column count inconsistencies with table header column count
# (Not documented in official rules list - MD057 appears to be missing or deprecated)
# MD058/blanks-around-tables - Tables should be surrounded by blank lines
MD058: true
# MD059/descriptive-link-text - Link text should be descriptive
MD059:
false
# Prohibited link texts
#prohibited_texts: ["click here", "here", "link", "more"]

View File

@@ -1,5 +1,5 @@
import type { VNode } from "vue";
import { defineComponent, h, computed } from "vue";
import { defineComponent, h } from "vue";
import NavbarDropdown from "@theme-hope/modules/navbar/components/NavbarDropdown";
import { I18nIcon } from "@theme-hope/modules/navbar/components/icons/index";
@@ -11,20 +11,17 @@ export default defineComponent({
setup() {
const dropdown = useNavbarLanguageDropdown();
const filteredDropdown = computed(() => {
const filteredDropdown = () => {
if (!dropdown.value) return null;
const filteredConfig = { ...dropdown.value };
if (filteredConfig.children) {
filteredConfig.children = filteredConfig.children.filter(item => {
// 过滤掉跳转到根目录的项目
return item.link !== '/' && item.link !== '/docs/' && !item.link?.endsWith('/docs/');
});
filteredConfig.children = filteredConfig.children.filter(item => item.link !== '/');
}
return filteredConfig;
});
};
//console.log("OldLanguageDropdown", dropdown.value);
//console.log("NewLanguageDropdown", filteredDropdown());
@@ -36,11 +33,11 @@ export default defineComponent({
{ class: "vp-nav-item" },
h(
NavbarDropdown,
{ config: filteredDropdown.value },
{ config: filteredDropdown() },
{
title: () =>
h(I18nIcon, {
"aria-label": filteredDropdown.value?.ariaLabel,
"aria-label": filteredDropdown()?.ariaLabel,
style: {
width: "1rem",
height: "1rem",

View File

@@ -14,6 +14,11 @@ export default defineUserConfig({
port: 3001,
locales: {
"/": {
lang: " ",
title: " ",
description: " ",
},
"/zh-cn/": {
lang: "zh-cn",
description: "文档",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -5,16 +5,6 @@ $vp-font: '-apple-system, BlinkMacSystemFont, "Noto Sans SC", "Segoe UI", Roboto
$vp-font-heading: 'Georgia, -apple-system, "Nimbus Roman No9 L", "PingFang SC", "Hiragino Sans GB", "Noto Serif SC", "Microsoft Yahei", "WenQuanYi Micro Hei", "ST Heiti", sans-serif';
$vp-font-mono: '"Sarasa Gothic", "Jetbrains mono", "Fira Code", "Noto Sans SC", Consolas, monospace, Menlo, "Courier New"';
.vp-hero-slide-down-button {
display: none !important;
visibility: hidden !important;
}
.vp-skip-link.sr-only {
display: none !important;
visibility: hidden !important;
}
html[lang="ja-JP"] {
$vp-font: "Helvetica Neue, Arial, Hiragino Kaku Gothic ProN, Hiragino Sans, Meiryo, sans-serif";
}

View File

@@ -1,137 +0,0 @@
---
order: 7
icon: devicon-plain:githubactions
---
# CI System Analysis
MAA leverages GitHub Actions to complete a large amount of automation work, including website building, automatic resource updates, final file building and release processes, etc. Over time, these CI workflows have gradually become nested, with some even pointing to other repositories. This document aims to provide a brief introduction for those who want to improve MAA's CI system.
Before reading this document, it's best to have a basic understanding of MAA's project structure and components.
::: tip
You can quickly navigate to the section you want to see by searching for CI file names within this page
:::
Workflow files are all stored under `.github/workflows`, and each file can be categorized into the following functional parts:
+ [Code Testing](#code-testing)
+ [Code Building](#code-building)
+ [Version Release](#version-release)
+ [Resource Updates](#resource-updates)
+ [Website Building](#website-building)
+ [Issues Management](#issues-management)
+ [Pull Requests Management](#pull-requests-management)
+ [MirrorChyan Related](#mirrorchyan-related)
+ [Others](#others)
Additionally, we use [pre-commit.ci](https://pre-commit.ci/) to implement automatic code formatting and image resource optimization, which runs automatically after creating PRs and generally requires no special attention.
## GitHub Actions Section
### Code Testing
`smoke-testing.yml`
This workflow is mainly responsible for basic testing of MaaCore, including resource file loading, simple task execution tests, etc.
Since test cases haven't been updated for a long time, this workflow is now basically used to ensure resource files don't contain errors and that MaaCore code doesn't have fatal errors (the kind that affects building).
### Code Building
`ci.yml`
This workflow is responsible for full code building work, including all MAA components. The build artifacts are runnable MAA instances.
In addition to the necessary MaaCore, Windows build artifacts include MaaWpfGui, macOS build artifacts include MaaMacGui, and Linux build artifacts include MaaCLI.
This workflow runs automatically on any new commit and PR. When triggered by a release PR, the build artifacts from this run will be used directly for release and will create a Release.
### Version Release
Version release is the necessary operation to publish updates to users, consisting of the following workflows:
+ `release-nightly-ota.yml` Release nightly builds
+ `release-ota.yml` Release stable/beta versions
+ `gen-changelog.yml` Generate changelog for stable/beta versions
+ `pr-auto-tag.yml` Generate tags for stable/beta versions
::: tip
The "ota" in the above file names stands for Over-the-Air, which is what we commonly call "incremental update packages". Therefore, MAA's release process actually includes building OTA packages for past versions.
:::
#### Nightly Builds
`release-nightly-ota.yml`
This workflow runs automatically at 22:00 UTC daily to ensure nightly build release frequency. Of course, you can also manually release when making changes that need verification.
Note that nightly builds are only released for Windows users; macOS and Linux users cannot receive nightly updates.
#### Stable/Beta Versions
The release process for these two channels is relatively more complex. We'll explain the role of each workflow by simulating a release process:
1. Create a PR from `dev` to `master` branch, and the PR name must be `Release v******`
2. `gen-changelog.yml` generates a changelog from the most recent stable/beta version to the current version (as a new PR)
3. Manually adjust the changelog and add brief descriptions
4. Merge the PR, triggering `pr-auto-tag.yml` to create tags and sync branches
5. The Release event triggers `release-ota.yml`, which builds OTA packages and uploads attachments after tagging master
### Resource Updates
This section of workflows is mainly responsible for MAA's resource updates and optimization, with the following specific workflows:
+ `res-update-game.yml` Executes periodically to pull game resources from specified repositories
+ `sync-resource.yml` Syncs resources to the MaaResource repository for resource updates
+ `optimize-templates.yml` Optimizes template image sizes
### Website Building
`website-workflow.yml`
This workflow is mainly responsible for building and publishing MAA's official website, including both the main page and documentation components.
Please note that website publishing is tightly bound to releases. Regular modifications to web components only trigger builds to ensure no errors occur, and actual deployment to Azure only happens during releases.
### Issues Management
`issue-checker.yml`
Uses regex matching to tag various Issues, categorizing and marking Issue content for easier viewing and management.
`issue-checkbox-checker.yml`
Uses regex matching to automatically close Issues that check "I have not read carefully".
If "I have not read carefully" is not checked, all checkboxes are collapsed.
`stale.yml`
Checks Bug Issues that have had no activity for more than 90 days, marks them and sends notifications, then closes them after 7 more days if still inactive.
### Pull Requests Management
`pr-checker.yml`
This workflow checks whether commit messages in PRs conform to [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) and whether they contain merge commits, providing reminders if these conditions are met.
### MirrorChyan Related
MirrorChyan is a paid update mirror service, with the following related workflows:
+ `mirrorchyan.yml` Sync update packages to MirrorChyan
+ `mirrorchyan_release_note.yml` Generate MirrorChyan Release Notes
### Others
`markdown-checker.yml`
Responsible for checking all Markdown files in the repository for invalid links.
`blame-ignore.yml`
Automatically ignores commits with commit messages containing `blame ignore` to keep repository history clean.
`cache-delete.yml`
Cleans up related caches after PR merges to save cache usage.

View File

@@ -5,15 +5,11 @@ icon: iconoir:developer
# Getting Started with Development
::: tip
This page mainly describes the PR workflow and MAA's file formatting requirements. If you want to learn specifically how to make changes to MAA's operational logic, please refer to the [Protocol Documentation](../protocol/)
:::
## Introduction to GitHub Pull Request Flow
## Introduction to GitHub Pull Request flow
### I don't know programming but just want to modify some JSON files/documents, how can I do it?
Welcome to the [Web-based PR Tutorial](./pr-tutorial.md) that anyone can understand (purely web-based on Github.com)
Welcome to the [GitHub Pull Request Tutorial](./pr-tutorial.md) that anyone can understand (purely web-based on Github.com)
### I can program, but I've never used GitHub/C++/..., how do I get started?
@@ -31,10 +27,10 @@ Welcome to the [Web-based PR Tutorial](./pr-tutorial.md) that anyone can underst
4. Download prebuilt third-party libraries
**Python environment required - search for Python installation tutorials if needed**
_(tools/maadeps-download.py is located in the project root)_
_maadeps-download.py is located in the project root_
```cmd
python tools/maadeps-download.py
python maadeps-download.py
```
5. Configure development environment
@@ -45,11 +41,11 @@ Welcome to the [Web-based PR Tutorial](./pr-tutorial.md) that anyone can underst
7. Configure Visual Studio settings
- Select `RelWithDebInfo` and `x64` in the top configuration bar (Skip for Release builds or ARM platforms)
- Right-click `MaaWpfGui` Properties Debug Enable native debugging (This enables breakpoints in C++ Core)
- Right-click `MaaWpfGui` -> Properties -> Debug -> Enable native debugging (This enables breakpoints in C++ Core)
8. Now you're ready to happily ~~mess around~~ start developing!
9. Commit regularly with meaningful messages during development
If you're not familiar with git usage, you might want to create a new branch for changes instead of committing directly to `dev`:
Beginners should create a new branch instead of committing directly to `dev`:
```bash
git branch your_own_branch
@@ -79,16 +75,16 @@ Welcome to the [Web-based PR Tutorial](./pr-tutorial.md) that anyone can underst
git fetch upstream
```
3. Rebase (recommended) or merge:
3. Rebase or merge:
```bash
git rebase upstream/dev # rebase
git rebase upstream/dev
```
or
```bash
git merge # merge
git merge
```
4. Repeat steps 7, 8, 9, 10.
@@ -97,15 +93,15 @@ Welcome to the [Web-based PR Tutorial](./pr-tutorial.md) that anyone can underst
After opening Visual Studio, Git operations can be performed using VS's built-in "Git Changes" instead of command-line tools.
:::
## MAA File Formatting Requirements
## MAA file formatting requirements
MAA uses a series of formatting tools to ensure that the code and resource files in the repository are visually unified for easy maintenance and reading.
Please ensure that it has been formatted before submission, or [enable Pre-commit Hooks for automatic formatting](#use-pre-commit-hooks-to-automatically-format-code).
Please ensure that it has been formatted before submission, or [enable Pre commit Hooks for automatic formatting](#use-pre-commit-hooks-to-automatically-format-code).
The currently enabled formatting tools are as follows:
| File Type | Format Tool |
|File Type | Format Tool|
| --- | --- |
| C++ | [clang-format](https://clang.llvm.org/docs/ClangFormat.html) |
| Json/Yaml | [Prettier](https://prettier.io/) |

View File

@@ -7,9 +7,7 @@ icon: bxs:bot
The action of Issue Bot is [issue-checker](https://github.com/zzyyyl/issue-checker), with configuration file [issue-checker.yml](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/.github/issue-checker.yml).
::: warning
Your pull request will be marked as `ambiguous` when you are not committing with Conventional Commits specification.
:::
**Note that your merge request will be marked as `ambiguous` when you are not committing with Commitizen specification.**
## Features
@@ -29,7 +27,7 @@ Your pull request will be marked as `ambiguous` when you are not committing with
Issue Bot will check the title of your pull request. Unless the title starts with one of the following keywords, the pull request will be marked as `ambiguous`.
- `build` `chore` `ci` `doc` `docs` `feat` `fix` `perf` `refactor` `rfc` `style` `test`
- `Merge` `merge` `Revert` `revert` `Reapply` `reapply`
- `Merge` `merge` `Revert` `revert`
### Triggering Manually
@@ -54,9 +52,7 @@ It is better to trigger Issue Bot with keywords instead of commands listed below
- `Duplicate of #{ISSUE_NUMBER}` will add `duplicate` label to the issue.
- **You can add some `skip` operations if your comment may confuse Issue Bot.**
::: info Note
<sup>1</sup> The `COMMIT_HASH` here needs to be the full 40 characters
:::
_Note<sup>1</sup>: The `COMMIT_HASH` here is the full 40-character hash._
#### Push

View File

@@ -3,99 +3,82 @@ order: 2
icon: teenyicons:linux-alt-solid
---
# Linux Compilation Tutorial
# Linux Compiling Tutorial
**This tutorial requires readers to have some Linux environment configuration ability and programming foundation!** If you only want to directly install MAA instead of compiling it yourself, please read [User Manual - Linux Emulators and Containers](../manual/device/linux.md).
**The tutorial requires some basic knowledge about Linux OS!**
If you just want to install MAA directly instead of compiling it yourself, please read [Emulator Support for Linux](../manual/device/linux.md).
::: info Note
MAA's build method is still under discussion. The content of this tutorial may be outdated. Please refer to the scripts in [GitHub workflow file](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/.github/workflows/ci.yml#L134). You can also refer to [AUR PKGBUILD](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=maa-assistant-arknights), [nixpkgs](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-assistant-arknights/package.nix).
Linux build of MAA is still under discussion, some of the content might be outdated, please follow the script in [GitHub workflow file](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/.github/workflows/ci.yml#L134), also reference [AUR PKGBUILD](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=maa-assistant-arknights), [nixpkgs](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-assistant-arknights/package.nix)
:::
::: info
Mac can use the `tools/build_macos_universal.zsh` script for compilation. It's recommended to refer to the README.md of the [MaaAssistantArknights/MaaMacGui](https://github.com/MaaAssistantArknights/MaaMacGui) project.
:::
## Compiling MAA
## Compilation Process
1. Download compilation dependencies
1. Download build depends
- Ubuntu/Debian
```bash
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20
sudo apt install cmake
```
```bash
sudo apt install gcc-12 g++-12 cmake zlib1g-dev
```
- Arch Linux
```bash
sudo pacman -S --needed cmake
# also, llvm 20 is needed.
# clang-20, clang++-20 are required to be found in PATH
```
```bash
sudo pacman -S --needed gcc cmake zlib
```
2. Build third-party libraries
2. Build or download third-party libraries
You can choose to download pre-built dependency libraries or compile from scratch
You may either download pre-built dependencies or build them from scratch
- Download pre-built third-party libraries (recommended)
- Download pre-built libraries (recommended)
> **Note**
> ~~Contains dynamic libraries compiled on relatively new Linux distributions (Ubuntu 22.04). If your system's libstdc++ version is older, you may encounter ABI incompatibility issues.~~
> After introducing cross compiling to lower the runtime requirement, only glibc 2.31 (aka. ubuntu 20.04) is required now.
> It contains shared objects built on a relatively new linux distro (Ubuntu 22.04), which may cause ABI incompatibility if you are working on a system with older version of libstdc++.
```bash
python tools/maadeps-download.py
python tools/linux-toolchain-download.py
python maadeps-download.py
```
If you find the libraries downloaded above cannot run on your system due to ABI version issues and you don't want to use container solutions, you can also try compiling from scratch
If this does not work for you due to ABI issue, and containerization is not an option, you may build them from scratch
- Build third-party libraries from scratch (will take considerable time)
- Build from source
```bash
git clone https://github.com/MaaAssistantArknights/MaaDeps
git submodule update --init --recursive
cd MaaDeps
# If the system is too old to install llvm 20, please consider using local build enviroment instead of cross compiling.
# The toolchain config under MaaDeps/vcpkg-overlay/triplet needs to be modified.
python linux-toolchain-download.py
python build.py
python build.py
```
3. Compile MAA
3. Build MAA
```bash
cmake -B build \
CC=gcc-12 CXX=g++-12 cmake -B build \
-DINSTALL_THIRD_LIBS=ON \
-DINSTALL_RESOURCE=ON \
-DINSTALL_PYTHON=ON \
-DCMAKE_TOOLCHAIN_FILE=cmake/linux/maa-x64-linux-toolchain.cmake
-DINSTALL_PYTHON=ON
cmake --build build
```
To install MAA to target location, note that MAA is recommended to run by specifying `LD_LIBRARY_PATH`, don't use administrator privileges to install MAA into `/usr`
> Now it shall be able to run without specifying `LD_LIBRARY_PATH`
To install MAA to the target location, note that MAA is recommended to run by specifying `LD_LIBRARY_PATH`, do not use administrator privileges to load MAA into `/`
```bash
cmake --install build --prefix <target_directory>
```
## Integration Documentation
## Integration
[~~Perhaps not really documentation~~](../protocol/integration.md)
[~~Maybe not a doc~~](../protocol/integration.md)
### Python
You can refer to the implementation of `__main__` in [Python demo](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/Python/sample.py)
Refer to the implementation of `__main__` in [Python demo](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/Python/sample.py)
### C++
### C
You can refer to the implementation in [CppSample](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/Cpp/main.cpp)
Refer to the implementation of [CppSample](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/Cpp/main.cpp)
### C Sharp
<!-- Do not use C#, MD003/heading-style: Heading style [Expected: atx; Actual: atx_closed] -->
You can refer to the implementation in [MaaWpfGui](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/MaaWpfGui/Main/AsstProxy.cs)
Refer to the implementation of [MaaWpfGui](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/MaaWpfGui/Main/AsstProxy.cs)

View File

@@ -3,116 +3,114 @@ order: 5
icon: ri:earth-fill
---
# Overseas Client Adaptation Tutorial
# Overseas Clients Adaptation
## Preparation
Before starting this tutorial, make sure you have:
1. Installed and properly configured the required software. There should be relevant information in the CN client or corresponding client's `readme.md` to ensure that supported features work properly.
2. Read the [Task Schema](../protocol/task-schema.md) and have a basic understanding of the meaning and usage of each field, and understand the meaning and usage of `@` and `#` type tasks.
3. Understand that content not mentioned or missing in overseas client `task.json` and template images will use CN client `task.json` and template images as fallbacks. Content in overseas client `task.json` will override and rewrite corresponding fields of CN client tasks.
4. Have sufficient English ability to read English logs and find missing images and other information through logs.
5. It's recommended to modify according to task chains. For example, for the `Award` task, gradually replace `template images` / `text` / `modify roi` step by step according to the `next` order of the `Award` task in CN client `task.json`, ensuring each step works properly after modification or can quickly identify errors. This avoids confusion about which step the program is stuck on when too many changes are made at once.
1. Installed and properly configured the required software. There should be information in the `readme.md` of the ZH-CN client or the corresponding client to ensure that the supported features work properly.
2. Read [Task Schema](../protocol/task-schema.md) and have a basic understanding of the meaning and usage of each field. You should also understand the meaning and usage of `@` and `#` in the code.
3. Understand that the `task.json` file and template image of the ZH-CN client will be used as alternatives when they are unmentioned or missing for the overseas client. The content in the `task.json` for the overseas client should be rewritten according to the fields of the ZH-CN task.
4. Have some English ability, be able to read English logs, and be able to find missing pictures and other information through the logs.
5. Understand that it is recommended to perform the modification individually according to the task chain. For example, to modify the Award task, you should modify the `template image`, `text`, and `roi` step by step in accordance with the order in its `next` field. This will ensure that every task is working normally after modification and errors can be easily spotted. Additionally, this can prevent confusion and forgetting which task the software is stuck on when too much content is modified at once.
### Pre-modification Preparation
### Preparation before making changes
Before making modifications, there are several preparation steps to note:
Before making changes, there are several preparations that need to be noted:
1. Refer to CN client task.json and ensure you have prepared template images and text content for overseas clients that differ from CN client.
2. Ensure you can access these images and text content at any time.
1. Refer to the ZH-CN client's `task.json` and make sure you have prepared the template images and text content for the overseas client.
2. Make sure you have ready access to these images and text content.
## Getting Screenshots
## Get screenshots
To get high-quality screenshots, please follow these guidelines:
1. Use the emulator's built-in screenshot tool to take and save screenshots.
2. Ensure screenshot dimensions are larger than `1280*720` with aspect ratio `16:9`.
3. Ensure screenshots don't contain any irrelevant content, such as taskbar, status bar, notification bar, etc.
4. Ensure screenshots contain all content that needs to be recognized.
1. Use the screenshot tool provided with the emulator to take and save screenshots.
2. Ensure that the size of the screenshot is at least `1280x720` and the aspect ratio is `16:9`.
3. Make sure the screenshot does not contain any extraneous content, such as the taskbar, status bar, or notification bar.
4. Make sure the screenshot includes all the content that needs to be recognized.
To crop images and get text/image `roi`, you need to install `python` and `opencv`, and download the `MaaAssistantArknights/tools/CropRoi/main.py` file.
To crop the image and get the text/image region of interest (ROI), you will need to install `Python` and `OpenCV`, and download the `MaaAssistantArknights/tools/CropRoi/main.py` file.
Then follow these steps:
Then, follow these steps:
1. Create new `src` and `dst` folders in the same directory as `main.py`.
2. Place **complete screenshots** that need resizing or text/image `roi` extraction into the `src` folder.
2. Place the **complete screenshot** of the text/image that needs to be resized or in need of a new ROI value into the `src` folder.
3. Run `main.py`.
4. Use mouse drag to select target range, try not to include irrelevant content.
5. After determining the range, press `S` to save, press `Q` to exit. Cropped images will be saved in the `dst` folder.
4. Select the target range by dragging the mouse, making sure not to include extraneous content.
5. Once the range is determined, press `S` to save and `Q` to exit. The cropped image will be saved in the dst folder.
For example, output after completing one crop:
For example, the output after completing a crop would be:
```log
``` log
src: Screenshot_xxx.png
dst: Screenshot_xxx.png_426,272,177,201.png
original roi: 476, 322, 77, 101,
amplified roi: 426, 272, 177, 201
```
Where:
In this example, `Screenshot_xxx.png` is the name of the full screenshot placed in the `src` folder, and `Screenshot_xxx.png_426,272,177,201.png` is the name of the cropped image.
`Screenshot_xxx.png` is the name of the complete screenshot placed in the `src` folder. `Screenshot_xxx.png_426,272,177,201.png` is the cropped image.
The `original roi` is the area selected by the mouse, while the `amplified roi` is the enlarged area. You will need the enlarged area, so you should use the `amplified roi` value to fill in the roi field in task.json.
`original roi` is the mouse-selected area. `amplified roi` is the enlarged area. You need the enlarged range, so fill the `roi` field in `task.json` with this value.
## Modify the template image
## Modifying Template Images
Before modifying template images, you need to open the corresponding client's template image folder and CN client's template image folder.
Before modifying the template image, you need to open the template image folder of the corresponding client and the template image folder of the ZH-CN client.
For example:
- EN client template image folder location: `MaaAssistantArknights\resource\global\YoStarEN\resource\template`.
- CN client template image folder location: `MaaAssistantArknights\resource\template`.
- The location of the template image folder for EN client is `MaaAssistantArknights\resource\global\YoStarEN\resource\template`.
- The location of the template image folder for the ZH-CN client is `MaaAssistantArknights\resource\template`.
Refer to template images mentioned in `task.json`, compare CN client and overseas client template images, and find templates missing in overseas client.
Refer to the template images mentioned in the `task.json` file, compare the template images of the ZH-CN client and the overseas client, and identify any missing templates in the overseas client.
Usually, except for logos and other images, templates containing text need to be replaced through screenshots. If image dimensions are significantly larger than corresponding CN client template images, you need to modify `roi` size.
Typically, template images containing text need to be replaced with screenshots, with the exception of images such as logos. If the size of the image is significantly larger than the corresponding template image in the ZH-CN client, you may need to modify the size of the `roi`.
Place captured and renamed template images into the corresponding client's template image folder.
Once you have captured and renamed the template image, you can place it in the template image folder of the corresponding client.
## Modifying Text Content
## Modify the text content
Before modifying text content, you need to open the corresponding server's `task.json` and CN client's `task.json`.
Before modifying the text content, you will need to open the `task.json` file for both the corresponding server and ZH-CN client.
For example:
- EN client `task.json` location: `MaaAssistantArknights\resource\global\YoStarEN\resource\tasks.json`.
- CN client `task.json` location: `MaaAssistantArknights\resource\tasks.json`.
- The location of `task.json` in EN client is `MaaAssistantArknights\resource\global\YoStarEN\resource\tasks.json`.
- The location of `task.json` for ZH-CN client is `MaaAssistantArknights\resource\tasks.json`.
Find the corresponding task and modify the `text` field to content displayed in the corresponding server. Note that recognized content can be a substring of complete in-game content.
To modify the text, locate the corresponding task and change the `text` field to the content displayed in the corresponding server. Keep in mind that the identified content can be a substring of the full content within the game. In general, you should replace any `text` containing text unless it is recognized as a pure ASCII character.
Usually, unless it's pure ASCII character recognition, `text` containing text needs to be replaced. If text length is significantly larger than CN client, you need to modify `roi` size, such as the length difference between `"任务"` and `"Mission"` being too large, requiring modification of overseas client task `roi` size.
If the text length is significantly longer than the ZH-CN client version, you may need to modify the size of the `roi` field. For example, if the difference in length between the `"任务"`(Mission in chinese) and the English word `"Mission"` is too large, you may need to modify the size of the `roi` for that mission in the overseas client.
If the corresponding overseas client `task.json` doesn't have the task, you need to add the task, only filling in the `text` field.
If the task does not exist in the `task.json` file of the corresponding overseas server, you will need to add it. Simply fill in the `text` field with the appropriate content.
## Modifying ROI Range
## Modify ROI range
1. Open the corresponding server's `task.json`, such as EN client location `MaaAssistantArknights\resource\global\YoStarEN\resource\tasks.json`
2. Find the corresponding task that needs `roi` range modification, use your prepared overseas game interface screenshots, and adjust `roi` range size according to `amplified roi`.
3. Usually, `roi` doesn't need modification, only when recognition content size difference with CN client is too large.
4. If the corresponding overseas client `task.json` doesn't have the task, add the task and write the `roi` field.
To modify the ROI range:
## Save Settings and Restart Software
1. Open the `task.json` file for the corresponding server, for example, the location of the EN client's `task.json` file is `MaaAssistantArknights\resource\global\YoStarEN\resource\tasks.json`.
2. Find the task that corresponds to the ROI range you need to modify, and use a screenshot of the overseas game interface to adjust the size of the `roi` range according to the amplified ROI.
3. Normally, you should not need to modify the `roi` range, but you may need to do so if the difference in size between the text and the Chinese client version is too large.
4. If the task does not exist in the `task.json` file of the corresponding overseas client, add the task and write the `roi` field with the appropriate values.
After modifications are complete, restart the software to reload files and make changes effective. Or create a `DEBUG.txt` file in the software directory before opening the software, so templates and files reload every time you click start, without needing restart.
## Save the settings and restart the software
Check for success:
After making the changes, you will need to save the settings and restart the software in order for the changes to take effect. To do this, you can either restart the software and reload the file, or create a new `DEBUG.txt` file in the software directory. This will cause the template and files to be reloaded every time you click the "Link Start" button, so you will not need to restart the software.
1. Check software operation to ensure it works normally on overseas clients.
2. If it doesn't work properly, check if modifications are correct or view log output to find error locations.
To check for success:
## Reading Logs
1. Test the operation of the software to ensure that it is functioning properly on the overseas server.
2. If it is not working properly, you will need to check if the changes are correct, or check the log output to determine what went wrong.
Sometimes after modifying `task.json`, we find the program still can't run correctly. In this case, we should check logs to find error locations and modify corresponding tasks.
## Interpreting the logs
Log file location is in the software root directory, filename `asst.log`. If you compiled MAA yourself, it's in `\x64\Release` or `x64\RelWithDebInfo`, depending on your compilation mode selection.
If you have modified the `task.json` file but the program is still not functioning correctly, it may be helpful to check the logs to find any errors and modify the corresponding task accordingly. The log file is typically located in the root directory of the software, and is named `asst.log`. If you compiled MAA yourself, it may be located in the `\x64\Release` or `\x64\RelWithDebInfo` directory, depending on the compilation mode you selected when compiling.
Here's a log example:
Interpreting the logs can be helpful in identifying any issues with the program. Here is an example log:
```log
``` log
[2022-12-18 17:43:17.535][INF][Px7ec][Tx15c8] {"taskchain":"Award","details":{"to_be_recognized":["Award@ReturnTo","Award","ReceiveAward","DailyTask","WeeklyTask","Award@CloseAnno","Award@CloseAnnoTexas","Award@TodaysSupplies","Award@FromStageSN"],"cur_retry":10,"retry_times":20},"first":["AwardBegin"],"taskid":2,"class":"asst::ProcessTask","subtask":"ProcessTask","pre_task":"AwardBegin"}
[2022-12-18 17:43:18.398][INF][Px7ec][Tx15c8] Call ` C:\Program Files\BlueStacks_nxt\.\HD-Adb.exe -s 127.0.0.1:5555 exec-out "screencap | gzip -1" ` ret 0 , cost 862 ms , stdout size: 2074904 , socket size: 0
[2022-12-18 17:43:18.398][INF][Px7ec][Tx15c8] Call ` C:\Program Files\BlueStacks_nxt\. \HD-Adb.exe -s 127.0.0.1:5555 exec-out "screencap | gzip -1" ` ret 0 , cost 862 ms , stdout size: 2074904 , socket size: 0
[2022-12-18 17:43:18.541][TRC][Px7ec][Tx15c8] OcrPack::recognize | roi: [ 500, 50, 300, 150 ]
[2022-12-18 17:43:18.541][TRC][Px7ec][Tx15c8] Ocr Pipeline with asst::WordOcr | enter
[2022-12-18 17:43:18.634][TRC][Px7ec][Tx15c8] Ocr Pipeline with asst::WordOcr | leave, 93 ms
@@ -124,21 +122,20 @@ Here's a log example:
[2022-12-18 17:43:19.144][TRC][Px7ec][Tx15c8] asst::ProcessTask::_run | enter
```
In this log, you can see:
In this log, you can see that:
- `taskchain` represents the currently running task.
- `details` is task content, including fields to be recognized (`to_be_recognized`), current retry count (`cur_retry`), and total retry count (`retry_times`).
- `first` represents task start.
- `taskid` is the task number.
- `class` and `subtask` represent task class and subtask respectively.
- `pre_task` represents the previous task.
- `"taskchain"` represents the task currently in progress.
- `"details"` is the content of the task, including the fields to be recognized (`to_be_recognized`) and the current number of retries (`cur_retry`) and the total number of retries (`retry_times`).
- `"first"` represents the start of the task.
- `"taskid"` is the task number.
- `"class"` and `subtask` represent the class and subtask of the task, respectively.
- `"pre_task"` represents the previous task.
In addition, the execution of the command (e.g. `Call`) and the `OCR` information (e.g. `OcrPack::recognize`) are recorded in the log.
Additionally, the log records command execution (like `Call`) and `OCR` information (like `OcrPack::recognize`).
For example, in this log, `"to_be_recognized"`,`"cur_retry":3,"retry_times":20` means that the task has been attempted to be recognized 10 times, and the maximum number of times is 20. After the maximum number of times is reached, the task will be skipped and an error will be reported, and the next task will be performed. If there are no issues with the previous task, it is likely that there is a problem with the recognition here. To troubleshoot this issue, you can check the tasks mentioned in the log to see if there is a corresponding template file, if the `text` field of the corresponding task is incorrect, or if the `roi` range for task recognition is incorrect, and make any necessary modifications.
In this log, `"to_be_recognized"`, `"cur_retry":3,"retry_times":20` indicates it has repeatedly tried recognition 3 times, with maximum recognition attempts of 20. After reaching maximum attempts, it will skip the task and report error, continuing to the next task. If previous tasks had no issues, we can basically determine there's a recognition problem here. We need to check tasks mentioned in the log to see if there's a corresponding `template file`, if the corresponding task's `text` is incorrect, if task recognition `roi` range is correct, to find and fix the problem.
By looking at the corresponding template image, you may find that there is a template for this image in the EN client template folder, but the size is larger than the image in template folder for the ZH-CN client . This could cause the `roi` in ZH-CN client to not be recognized in the EN client, so you may need to modify the corresponding task's `roi` in the EN client's `task.json` file to match the size of the image in the EN client.
By checking the corresponding template image, we found there's a template for this image in the EN client template folder, but it's significantly larger than the CN client image, causing CN client's `roi` to fail recognition on EN client. So we need to modify the corresponding task `roi` in EN client's `task.json` to match EN client image size.
## Submit your changes
## Submit Your Changes
Please refer to [GitHub Pull Request Guide](./pr-tutorial.md)
Check out [Github Pull Request Guide](./pr-tutorial.md)

View File

@@ -3,24 +3,24 @@ order: 3
icon: mingcute:git-pull-request-fill
---
# Web-based PR Tutorial
# GitHub Pull Request User Guide
A GitHub Pull Request guide that even beginners can understand (\*´▽ )
This document is machine-translated. If you have the ability, please refer to the Chinese version. We would greatly appreciate any errors or suggestions for improvement.
::: warning
This tutorial simplifies many concepts to make them accessible to more people. It includes some ~~inelegant but simple~~ operations and not entirely accurate explanations. Please go easy on us, experts.
If you have some git experience and programming background, ~~then why are you reading this~~, you can check out the more advanced tutorial [GitHub Pull Request Process Overview](./development.md)
Many concepts in this tutorial have been simplified in order to make it more accessible to a wider audience, even at the expense of some elegance and accuracy.
For those who have experience using Git and programming knowledge, you may refer to the more advanced tutorial in [Development](./development.md)
:::
## Basic Concepts and Terminology
## Basic concepts and terminology
This section might be a bit dry. Feel free to skip to the practical section below and come back here if you need clarification.
This chapter contains slightly dry content. If you're not interested, you can skip directly to the practical section below. If there is anything you don't understand, you can come back to read this chapter later.
### Repository
Abbreviated as "repo", the place where we store our code and other resource files.
"Repo" is short for "repository", which is the place where we store our code and other resource files.
👇 You can simply understand this webpage and all its contents as MAA's repository (we generally call it MAA's main repository)
👇 You can think of the current web page and all of its contents as the repository for MAA (we usually refer to it as MAA's main repository).
```component Image1
{
@@ -35,12 +35,11 @@ Abbreviated as "repo", the place where we store our code and other resource file
### Fork
Literally means to copy. Fork a copy of MAA's code so you can make subsequent modifications without breaking the original.
Although "copy" in Chinese might first remind us of the "copy" operation, "fork" doesn't have a clear translation, so we usually use the English term directly, like "fork a copy of the code."
To fork, literally meaning to make a copy of MAA's code, and then perform subsequent modifications and operations to avoid damaging the original repository.
Since it's a copy, it becomes `MAA (1)` (just kidding)
To distinguish from the original repository, we generally call the original MAA repository the "main repository" or "upstream repository."
Since everyone can fork their own copy, the copied version is called a "personal repository" or "origin repository."
Since it's a copy, let's assume it's called `MAA (1)`.
To distinguish it from the original repository, we usually refer to the original MAA repository as "main repository" or "upstream".
Since everyone can make a copy of their own, the copied repository is called a "personal repository" or "origin".
```component Image1
{
@@ -55,12 +54,11 @@ Since everyone can fork their own copy, the copied version is called a "personal
### Pull Request
Abbreviated as PR. "Pull request" sounds strange when literally translated, ~~and it's too many characters to type~~, so everyone usually just says "make a PR."
Following the above, after you fork your personal repository and make modifications, how do you contribute your changes to the main repository? This is when you can open a PR to request that your modifications be added to the main repository.
Continuing from the previous section, after you have made changes to your forked personal repository, how do you provide the changes to the main repository? This is when you can open a pull request (PR) to request that your modified content be added to the main repository.
Of course, since it's a "request," it naturally needs approval. MAA Team members might provide feedback on your modifications, though our opinions aren't necessarily always correct - let's discuss reasonably~
Of course, since it's a "request", it naturally requires approval. MAA Team may provide feedback on your modifications, but our feedback may not necessarily be entirely correct. Let's have a reasonable discussion together~
👇 Below are PRs currently submitted by contributors, waiting for approval
👇 The following are the PRs currently submitted by contributors and awaiting approval from MAA Team.
```component Image1
{
@@ -75,14 +73,12 @@ Of course, since it's a "request," it naturally needs approval. MAA Team members
### Conflict
Imagine there's a file A in the main repository with content "111."
You fork a copy and change its content to "222," but just as you're about to submit a PR, someone else also forks a copy, submits a PR, and changes file A to "333."
Now we see that both of you modified file A differently. Whose version should we listen to? This is a Conflict.
Conflicts are somewhat troublesome to resolve. This section only explains the concept to help you understand what's happening when you encounter one.
Assuming that there is a file called A in the main repository with the content 111. You forked a copy and changed its content to 222. However, just as you were about to submit the PR, another person named Zhangsan forked a copy and submitted a PR with changes to the A file, changing it to 333.
Now we have a conflict, as both of you have modified the A file but in different ways. This conflict can be difficult to resolve, and here we are only explaining the concept to help you understand what has happened when you encounter it, without going into the details of the solution.
## Complete Web-based PR Process
## Full Process of Pure Web-based PR Operation
1. First, enter MAA's main repository and click the Fork button in the upper right corner to fork a copy of the code
1. First, go to the MAA main repository and click the button in the top right corner to fork a copy of the code.
```component Image1
{
@@ -95,7 +91,7 @@ Conflicts are somewhat troublesome to resolve. This section only explains the co
}
```
2. Then directly click "Create Fork"
2. Then, click on 'Create Fork' directly.
```component Image1
{
@@ -108,49 +104,170 @@ Conflicts are somewhat troublesome to resolve. This section only explains the co
}
```
3. You'll arrive at your personal repository. You can see the title is "YourName/MaaAssistantArknights" with small text below saying "forked from MaaAssistantArknights/MaaAssistantArknights"
3. You will be taken to your personal repository, which will have a title of "your_name/MaaAssistantArknights", with a small note below stating "forked from MaaAssistantArknights/MaaAssistantArknights" (copied from the MAA main repository).
4. Find the file you want to modify. You can click "Go to file" for global search, or browse through the folders below if you know where the file is
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-3-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-3-dark.png"
}
]
}
```
5. After opening the file, directly click the ✏️ in the upper right corner of the file to edit
4. Find the file you want to edit. You can click 'Go to file' to search globally, or you can browse through the folders below if you know where the file is located.
6. Start editing! (For resource files, we recommend testing modifications in your local MAA folder first, confirming they work before pasting into the webpage to avoid errors)
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-4-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-4-dark.png"
}
]
}
```
7. After editing, click the button in the upper right corner to open the commit page and write what you changed
5. After opening the file, click on the ✏️ icon on the top right corner of the file to start editing.
We have a simple commit title [naming format](https://www.conventionalcommits.org/en/v1.0.0/). It's best to follow it, but if you really can't understand it, you can write something simple first.
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-5-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-5-dark.png"
}
]
}
```
8. Have a second file to modify? Discovered an error after finishing? No problem! Just repeat steps 4-7!
6. Make your changes! (If it's a resource file, we recommend testing the changes in your local MAA folder before pasting them in the web page to avoid errors).
7. Once you've finished editing, click the button 👇 in the top right corner to open the commit page and write a brief description of what you changed.
9. After all modifications are complete, make a PR! Click "Code" to return to your **personal repository's** homepage
If there's a "Compare & Pull Request" button, that's great - click it directly!
If not, don't worry - click the "Contribute" button below, then "Open Pull Request" - it's the same thing.
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-7-1-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-7-1-dark.png"
}
]
}
```
10. You'll arrive at the main repository's PR page. Please verify that what you want to PR is what you intend to submit.
As shown in the image, there's a leftward arrow in the middle, requesting to merge the right side's PersonalName/MAA dev branch into the main repository/MAA dev branch.
Scrolling down shows the differences between these two branches - what you've changed.
We have a simple commit title [naming format](https://www.conventionalcommits.org/zh-hans/v1.0.0/), which you should try to follow. However, if you find it difficult to understand, you can just write something for now.
Then write a title and specific content of your modifications, then click confirm.
PR titles also need to follow the [naming format](https://www.conventionalcommits.org/en/v1.0.0/). If you still can't understand it, you can write something simple first.
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-7-2-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-7-2-dark.png"
}
]
}
```
11. Wait for MAA Team members to review! They might also provide feedback
👇 For example (purely for entertainment, don't take it seriously)
8. Need to edit another file? Made a mistake and want to change it again? No problem! Simply repeat steps 4-7 for the other file.
9. When all changes are made, create a Pull Request by going to the Pull Request tab in your personal repository.
If there is a "Compare & Pull Request" button, that's great, just click it!
If not, don't worry, clicking "Open Pull Request" below is also the same.
12. If team members say to modify some small issues, return to **your personal repository** and repeat steps 4-7!
Note: you don't need to repeat steps 1-2 (re-fork) and steps 9-10 (re-Pull Request). Your current Pull Request is still pending review, and subsequent modifications will directly enter this Pull Request.
👇 For example, you can see an additional modification entry at the bottom
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-9-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-9-dark.png"
}
]
}
```
13. Once team members approve, everything is complete! Your modifications have entered MAA's main repository!
10. Now you are in the main repository, please double-check the changes you want to PR.
As shown in the figure, there is a leftward arrow, which means you want to merge the dev branch from your forked repository "your_name/MAA" to the dev branch of the main repository "MAA".
Scrolling down shows the differences between these two branches, indicating what changes you have made.
14. Next time you want to submit another PR, first return to your personal repository's homepage and click "Sync fork" to synchronize your repository with the main repository.
Note here: if there's a red "Discard 1 commit," click the red one; if not, then click the green "Update branch."
You can then repeat steps 4-10 to make modifications again.
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-10-1-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-10-1-dark.png"
}
]
}
```
**After version release**, your GitHub avatar will automatically be added to the contributors list. Thank you very much for your selfless contributions!
~~Why are they all anime characters? Oh wait, I am too, never mind then~~
Then, write a title and description of your changes, and click "Create Pull Request".
The PR title should also follow the [naming format](https://www.conventionalcommits.org/zh-hans/v1.0.0/). However, if you still don't understand it, you can also just write something for now.
::: tip Contributors
Thanks to all friends who participated in development/testing. Everyone's help makes MAA better and better! (\*´▽ )
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-10-2-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-10-2-dark.png"
}
]
}
```
11. Just wait for the MAA Team members to review it! Of course, they may also provide some comments,
👇 for example (for entertainment purposes only, do not take it seriously):
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-11-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-11-dark.png"
}
]
}
```
12. If they request further changes, go back to **your personal repository** and repeat steps 4-7!
Note that you do not need to redo step 1-2 (re-fork) or step 9-10 (re-Pull Request), your current Pull Request is still pending review, and subsequent changes will be added directly to this Pull Request.
👇 For example, you can see that "revised demo" has been added at the bottom.
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-12-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-12-dark.png"
}
]
}
```
13. Once the experts approve the PR, you're all set! Your changes have been merged into the main MAA repository!
14. If you want to submit another PR next time, please first go back to the homepage of your personal repository and click 'Sync fork' to synchronize your repository with the main repository.
Note here: If there is a red 'Discard 1 commit', click the red one. If there isn't, then click the green 'Update branch'.
Next, you can repeat steps 4-10 to make further modifications.
```component Image1
{
"imageList": [
{
"light": "images/zh-cn/pr-tutorial/pr-14-1-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-14-1-dark.png"
},
{
"light": "images/zh-cn/pr-tutorial/pr-14-2-light.png",
"dark": "images/zh-cn/pr-tutorial/pr-14-2-dark.png"
}
]
}
```
**After the version is released**, your GitHub avatar will automatically be added to the contributors list. Thank you very much for your selfless dedication!
::: tip Contributors/Participators
Thank you to everyone involved in development and testing. Your help is going to ~~Make MAA Great Again~~! (\*´▽ )
[![Contributors](https://contributors-img.web.app/image?repo=MaaAssistantArknights/MaaAssistantArknights&max=105&columns=15)](https://github.com/MaaAssistantArknights/MaaAssistantArknights/graphs/contributors)
:::

View File

@@ -28,7 +28,7 @@ type = "StartUp" # The type of the task
params = { client_type = "Official", start_game_enabled = true } # The parameters of the task
```
The specific task types and parameters can be found in the [MAA Integration Document][task-types]. Note that maa-cli does not validate parameter names and values, and no error message will be generated even if an error occurs unless MaaCore detects an error at runtime.
The specific task types and parameters can be found in the [MAA Integration Document][task-types]. Note that maa-cli does not validate parameter names and values, and no error message will be generated even if an error occurs unless MaaCore` detects an error at runtime.
### Task variants and conditions
@@ -61,9 +61,9 @@ params = { plan_index = 2 }
The `condition` field is used to determine whether the variant should be used,
and the `params` field of the matched variant will be merged into the parameters of the task.
**Note**: If the `filename` field is a relative path, it will be relative to `$MAA_CONFIG_DIR/infrast`. Additionally, the custom infrastructure plan file will not be read by `maa-cli` but by MaaCore. Therefore, the file format must be `JSON` and the time period defined in the file will not be used to select the corresponding sub-plan. You must specify the `plan_index` field in the task parameters to use the correct infrastructure plan in the corresponding time period. This ensures that the correct infrastructure plan is used at the appropriate time.
**Note**: If the `filename` field is a relative path, it will be relative to `$MAA_CONFIG_DIR/infrast`. Besides, the custom infrastructure plan file will not be read by `maa-cli` but MaaCore. So the format of the file must be `JSON` and the time period defined in the file will not be used to select the corresponding sub-plan. So you must specify the `plan_index` field in the parameters of the task to use the correct infrastructure plan in the corresponding time period. This will ensure that the correct infrastructure plan is used in the appropriate time period.
Besides the `Time` condition, there are also `DateTime`, `Weekday`, and `DayMod` conditions.
Besides of `Time` condition, there are also `DateTime`, `Weekday`, `DayMod` conditions.
`DateTime` condition is used to specify a specific date-time period,
`Weekday` condition is used to specify some days in a week,
`DayMod` condition is similar to `Weekday`, but the period can be specified by `divisor` and `remainder`.
@@ -85,13 +85,13 @@ params = { stage = "CE-6" }
params = { stage = "1-7" }
```
All the above conditions related to time have a `timezone` field, which can be an offset from UTC (e.g., `8` for UTC+8) or a client type (e.g., `"Official"`). Note that the official server timezone is UTC+4, not UTC+8, because the game day starts at 04:00:00 rather than 00:00:00. If timezone is omitted, your local system timezone is used.
All the above conditions related to time have a `timezone` field, which is used to specify the timezone of the condition. The value of `timezone` can be an offset of UTC, like `8` or `-7`, or a name of the client type of game, like `Official`. Note, even though the official server is in China, the timezone of the official server is `UTC+4` instead of `UTC+8`, because the start of the game day is `04:00:00` instead of `00:00:00`. When the `timezone` is omitted, the condition will be matched in the local timezone of the system.
Besides of above conditions, there is a condition `OnSideStory` which depends on hot update resource to check if there is any opening side story. Thus, the condition of fight `SL-8` can be simplified as `{ type = "OnSideStory", client = "Official" }`, where the `client` is the client type of game.
In addition to the above conditions, there's a `OnSideStory` condition that uses hot-update resources to check if there are any active events. For example, the condition to farm `SL-8` during a summer event can be simplified to `{ type = "OnSideStory", client = "Official" }`, where `client` is your game client type. Using this condition means you only need to update the stage to farm when an event changes, without manually editing event dates.
Beside of above basic condition, `{ type = "And", conditions = [...] }` `{ type = "Or", conditions = [...] }`, and `{ type = "Not", condition = ... }` can be used for logical combination of conditions.
Besides the basic conditions, you can use `{ type = "And", conditions = [...] }`, `{ type = "Or", conditions = [...] }`, and `{ type = "Not", condition = ... }` for logical combinations.
By combining these conditions, you can define infrastructure plans spanning multiple days. Here's an example of 6 plans for 2 days:
By the combination of of above conditions, you can define an infrastructure plan for multiple days,
here is an example of 6 plans for 2 days:
```toml
[[tasks]]
@@ -109,14 +109,16 @@ filename = "normal.json"
condition = {
type = "And",
conditions = [
# The divisor specifies the period, the remainder specifies the offset
# The offset equals num_days_since_ce % divisor
# num_days_since_ce is the number of days since Common Era (0001-01-01 is day 1)
# You can get the current day's offset with `maa remainder <divisor>`
# For 2024-01-27, num_days_since_ce is 738,912
# The offset is 738,912 % 2 = 0, so this condition matches on 2024-01-27
# The divisor use to specify the period, the remainder use to specify the offset
# The offset is equal to num_days_since_ce % divisor
# The num_days_since_ce is the number of days since the Common Era, 0001-01-01 is the first day
# The offset of current day can be got by `maa remainder <divisor>`
# for 2024-01-27, num_days_since_ce is 738,912,
# the offset of 2024-01-27 is 738,912 % 2 = 0
# so this condition will be matched on 2024-01-27
{ type = "DayMod", divisor = 2, remainder = 0 },
{ type = "Time", start = "04:00:00", end = "12:00:00" },
]
}
params = { plan_index = 0 }
@@ -134,7 +136,7 @@ params = { plan_index = 1 }
# The third shift, 20:00:00 (first day) - 04:00:00 (second day)
[[tasks.variants]]
# Note: we must use Or condition here to properly handle the time across midnight
# Note, we must use Or condition here, otherwise the second day 00:00:00 - 04:00:00 will not be matched
condition = {
type = "Or",
conditions = [
@@ -190,9 +192,9 @@ condition = {
params = { plan_index = 5 }
```
With the default strategy, if multiple variants are matched, only the first one will be used. If no condition is given, the variant will always be matched. So you can put a variant without condition at the end as a default case.
With the default strategy, if multiple variants are matched, only the first one will be used. If the condition is not given, the variant will always be matched. So you can put a variant without condition at the end of variants.
The strategy for matching variants can be changed with the `strategy` field:
The strategy of matching variants can be changed by `strategy` field:
```toml
[[tasks]]
@@ -224,11 +226,11 @@ params = { stage = "SL-8" }
condition = { type = "DateTime", start = "2023-08-01T16:00:00", end = "2023-08-21T03:59:59" }
```
This example will yield the same stage selection as the previous one, but will additionally use expiring medicine on Sunday night.
With the `merge` strategy, if multiple variants are matched, the parameters of all matched variants will be merged. If multiple variants have the same parameter keys, the later ones will override earlier ones.
The outcome stage of this example should be identical to the previous one, but expiring medicine will be used on Sunday night additionally.
With the `merge` strategy, if multiple variants are matched, the parameters of all matched variants will be merged. If multiple variants have the same parameters, the last one will be used.
If no variant is matched, the task will not be executed,
which is useful when you want to only run a task under certain conditions:
which is useful when you want to only run a task in some conditions:
```toml
# Mall after 18:00
@@ -239,9 +241,9 @@ type = "Mall"
condition = { type = "Time", start = "18:00:00" }
```
### User Input
### User input
For some tasks, you might want to input values at runtime rather than hardcoding them in the task file. You can set parameters to `Input` or `Select` type:
In some cases, you may want to input some value at runtime, instead of hard code it in the task file. Such as the stage to fight, the item to buy, etc. You can specify the value as `Input` or `Select` type:
```toml
[[tasks]]
@@ -259,9 +261,9 @@ alternatives = [
"SL-7", # will be displayed as "1. SL-7"
{ value = "SL-8", desc = "Manganese Ore" } # will be displayed as "2. SL-8 (Manganese Ore)"
]
default_index = 1 # the index of default value, start from 1, if not given, empty input will re-prompt
default_index = 1 # the index of default value, start from 1, if not given, empty value will be re-prompt
description = "a stage to fight in summer event" # description of the input, optional
allow_custom = true # whether to allow custom value input, default is false; if true, non-integer inputs are treated as custom values
allow_custom = true # whether allow input custom value, default to false, if allow, non-integer value will be treated as custom value
# Task without input
[[tasks.variants]]
@@ -271,29 +273,30 @@ params = { stage = "CE-6" }
# Input a stage to fight
[[tasks.variants]]
# Set the stage to an `Input` type with default value and description
# Set the stage to a `Input` type with default value and description
[tasks.variants.params.stage]
default = "1-7" # default value of stage, optional (if not given, empty input will re-prompt)
default = "1-7" # default value of stage, optional (if not given, user can input empty value to re-prompt)
description = "a stage to fight" # description of the input, optional
# query the medicine to use only when stage is 1-7
[tasks.variants.params.medicine]
# a parameter can be conditional based on other parameter values
# the condition uses a table where keys are other parameter names and values are the expected values
# this condition means "only prompt for medicine when stage is 1-7"
# a parameter can be optional with `optional` field
# if the condition is not matched, the parameter will be ignored
# the `condition` field can be used to specify the condition of the parameter
# where the condition can be a table, whose keys are name of other parameters and values are the expected value
conditions = { stage = "1-7" }
default = 1000
description = "medicine to use"
```
For an `Input` type, a prompt will be shown to ask the user to input a value. If a default value is given, it will be used when the user inputs an empty value; otherwise, it will re-prompt.
For a `Select` type, a prompt will be shown to ask the user to input an index or custom value (if `allow_custom` is `true`). If a default index is given, it will be used when the user inputs an empty value; otherwise, it will re-prompt.
For an `Input` type, a prompt will be shown to ask the user to input a value. If the default value is given, it will be used if the user inputs an empty value, otherwise, it will re-prompt.
For `Select` type, a prompt will be shown to ask the user to input an index or custom value (if `allow_custom` is `true`). If the default index is given, it will be used if the user inputs an empty value, otherwise, it will re-prompt.
The `--batch` option can be used to run tasks in batch mode, which will use default values for all inputs and error if no default value is given.
`--batch` option can be used to run tasks in batch mode, which will use the default value for all inputs and panic if no default value is given.
## MaaCore Related Configurations
## MaaCore related configurations
The MaaCore configuration files are called "Profiles" and located in the `$MAA_CONFIG_DIR/profiles` directory. Each file in this directory is a profile, with the default being `default.toml`. To use a different profile, specify it with the `-p` or `--profile` option.
The related configuration files of MaaCore is called "Profile" and located in `$MAA_CONFIG_DIR/profiles` directory. Each files in this directory is a profile, while the default profile is `default.toml`. If you want to use a profile other than the default one, you can specify it by `-p` or `--profile` option.
The currently available configurations are:
@@ -322,159 +325,152 @@ kill_adb_on_exit = false
### Connection
The `connection` section specifies how to connect to the game:
The `connection` section is used to specify how to connect to the game:
```toml
[connection]
adb_path = "adb" # path to adb executable, default is "adb" (uses PATH)
address = "emulator-5554" # device address like "emulator-5554" or "127.0.0.1:5555"
config = "General" # connection configuration, rarely needs changing
adb_path = "adb" # the path of adb executable, default to "adb", which means use adb in PATH
address = "emulator-5554" # the address of device, such as "emulator-5554" or "127.0.0.1:5555"
config = "General" # the config of maa, should not be changed most of time
```
`adb_path` is the path to the `adb` executable - you can set its absolute path or leave it empty to use it from PATH. Most emulators include `adb`, so you can use their built-in version without installing separately. `address` is the address used by `adb`. For emulators, use `127.0.0.1:[port]` - common emulator ports are listed in the [FAQ][emulator-ports]. If no address is specified, maa-cli tries to find a device with `adb devices`, using the first one found or defaulting to `emulator-5554` if none are found. `config` specifies platform/emulator configurations - defaults to `CompatPOSIXShell` on Linux, `CompatMac` on macOS, and `General` on other platforms. More options are in the resource folder's `config.json`.
`adb_path` is the path of `adb` executable, you can set it to the absolute path of `adb` or or leave it empty if it is in PATH. The `address` is the address of the device used by `adb`, like `emulator-5554` or `127.0.0.1:[port]`, the port of some common emulators can be found in the [MAA FAQ][emulator-ports]. If the `address` is absent, the cli will try to find the device automatically by `adb devices`, if there are multiple online devices, the first one will be used. If cli can not find any device, it will try to use the default address `emulator-5554`. The `config` is used to specify some configurations of the host and emulator, whose default value is `CompatMac` on macOS, `CompatPOSIXShell` on Linux and `General` on other platforms. More optional configs can be found in `config.json` in the resource directory.
For common emulators, you can use `preset` for predefined configurations:
For some common emulators, you can use `preset` to use predefined configurations:
```toml
[connection]
preset = "MuMuPro" # Use MuMu Pro emulator preset
adb_path = "/path/to/adb" # Override the preset's adb path if needed (optional)
address = "127.0.0.1:7777" # Override the preset's address if needed (optional)
preset = "MuMuPro"
adb_path = "/path/to/other/adb" # override predefined adb executable path
address = "127.0.0.1:7777" # override the predefined address
```
Currently only `MuMuPro` preset is available. Issues and PRs for more presets are welcome.
Currently, there is only one preset `MuMuPro` for emulators. Issue and PR are welcome for the new preset.
#### Special Presets
There are two special presets: `PlayCover (macOS)` and `Waydroid (Linux)`
- `PlayCover` is for connecting to iOS apps running natively on macOS through PlayCover. In this case, `adb_path` is ignored and `address` is the address of `PlayTools`. See [PlayCover documentation][playcover-doc] for details.
- `Waydroid` is for connecting to Android apps running natively on Linux through Waydroid. `adb_path` is still required. See [Waydroid documentation][waydroid-doc] for details.
There is a special preset `PlayCover`, used for the iOS app running on macOS by PlayCover. In this case, `adb_path` is ignored and `address` is used to specify the address of `MaaTools` set in `PlayCover`, more details can be found in the [PlayCover documentation][playcover-doc].
### Resource
The `resource` section specifies which resources MaaCore should load:
The `resource` section is used to specify the resource to use:
```toml
[resource]
global_resource = "YoStarEN" # Non-Chinese resources
platform_diff_resource = "iOS" # Non-Android resources
user_resource = true # Whether to load user-defined resources
global_resource = "YoStarEN" # the global resource to use
platform_diff_resource = "iOS" # the platform diff resource to use
user_resource = true # whether use user resource
```
When using a non-Simplified Chinese game client, set `global_resource` to load non-Chinese resources. When using an iOS client, set `platform_diff_resource` to `iOS`. Both are optional - leave empty to not load these resources. These are also auto-set based on your `startup` task's `client_type` and when using `PlayTools` connection. To load user-defined resources, set `user_resource` to `true`, which loads resources from `$MAA_CONFIG_DIR/resource`.
When your game is not in Simplified Chinese, you should set `global_resource` to non-Chinese resource. If you connect to the game with `PlayCover`, you should set `platform_diff_resource` to `iOS`.
Leave those two fields empty if you don't want to use global resource or platform diff resource. Besides, those two fields will also be set up automatically by maa-cli based on your task and connection type.
Lastly, if you want to use user resources, you should set `user_resource` to `true`. When `user_resource` is `true`, maa-cli will try to find user resources in `$MAA_CONFIG_DIR/resource` directory.
### Static options
The `static_options` section configures MaaCore static options:
The `static_options` section is used to configure MAA static options:
```toml
[static_options]
cpu_ocr = false # Whether to use CPU OCR (enabled by default)
gpu_ocr = 1 # GPU ID for GPU OCR; leave empty to use CPU OCR
cpu_ocr = false # whether use CPU OCR, CPU OCR is enabled by default
gpu_ocr = 1 # the ID of your GPU, leave it to empty if you don't want to use GPU OCR
```
### Instance options
The `instance_options` section configures MaaCore instance options:
The `instance_options` section is used to configure MAA instance options:
```toml
[instance_options]
touch_mode = "ADB" # Touch mode: "ADB", "MiniTouch", "MaaTouch", or "MacPlayTools"
deployment_with_pause = false # Whether to pause game during deployment
adb_lite_enabled = false # Whether to use adb-lite
kill_adb_on_exit = false # Whether to kill adb on exit
touch_mode = "ADB" # touch mode to use, can be "ADB", "MiniTouch", "MaaTouch" or "MacPlayTools" (only for PlayCover)
deployment_with_pause = false # whether pause the game when deployment
adb_lite_enabled = false # whether use adb-lite
kill_adb_on_exit = false # whether kill adb when exit
```
Note: When using `PlayTools` connection, `touch_mode` is forced to `MacPlayTools` regardless of setting.
Note: If you connect to the game with `PlayCover`, the `touch_mode` will be ignored and `MacPlayTools` will be used.
## CLI Related Configurations
## CLI related configurations
CLI-related configurations should be in `$MAA_CONFIG_DIR/cli.toml`. Current configurations include:
The CLI related configurations should be located in `$MAA_CONFIG_DIR/cli.toml`. Currently, it only contains one section: `core`:
```toml
# MaaCore install and update configurations
# MaaCore install and update configurations
[core]
channel = "Stable" # Update channel: "Alpha", "Beta", or "Stable" (default)
test_time = 0 # Time to test mirror speeds in seconds; 0 to skip, default is 3
# API URL to query latest MaaCore version; leave empty for default
api_url = "https://github.com/MaaAssistantArknights/MaaRelease/raw/main/MaaAssistantArknights/api/version/"
# Component installation config (not recommended to change)
channel = "Stable" # update channel, can be "Stable", "Beta" or "Alpha"
test_time = 0 # the time to test download mirrors in seconds, 0 to skip
# the url to query the latest version of MaaCore, leave it to empty to use default url
apit_url = "https://github.com/MaaAssistantArknights/maa-cli/raw/version/"
[core.components]
library = true # Whether to install MaaCore library
resource = true # Whether to install MaaCore resources
library = true # whether install MaaCore library
resource = false # whether install resource resource
# CLI update configurations
[cli]
channel = "Stable" # Update channel: "Alpha", "Beta", or "Stable" (default)
# API URL to query latest maa-cli version; leave empty for default
channel = "Stable" # update channel, can be "Stable", "Beta" or "Alpha"
# the url to query the latest version of maa-cli, leave it to empty to use default url
api_url = "https://github.com/MaaAssistantArknights/maa-cli/raw/version/"
# URL to download prebuilt binaries; leave empty for default
# the url to download prebuilt binary, leave it to empty to use default url
download_url = "https://github.com/MaaAssistantArknights/maa-cli/releases/download/"
[cli.components]
binary = true # Whether to install maa-cli binary
binary = true # whether install maa-cli binary
# Resource hot update configurations
# hot update resource configurations
[resource]
auto_update = true # Whether to auto-update resources before running tasks
warn_on_update_failure = true # Whether to warn instead of error on update failure
backend = "libgit2" # Hot update backend: "git" or "libgit2"
auto_update = true # whether auto update resource before running task
warn_on_update_failure = true # Whether to warn on update failure instead of panic
backend = "libgit2" # the backend of resource, can be "libgit2" or "git"
# Remote repository configuration
# the remote of resource
[resource.remote]
branch = "main" # Branch of remote repository
# Repository URL; leave empty for default
# GitHub repositories support both HTTPS and SSH; HTTPS recommended
url = "https://github.com/MaaAssistantArknights/MaaResource.git"
# url = "git@github.com:MaaAssistantArknights/MaaResource.git"
# If using SSH, you need to provide authentication:
# 1. Using ssh-agent (recommended)
# use_ssh_agent = true # Use ssh-agent for authentication
# 2. Using SSH key file
ssh_key = "~/.ssh/id_ed25519" # Path to SSH key
# If your key is password-protected:
passphrase = "password" # Passphrase for SSH key
# Storing plaintext passwords is insecure. Alternatives:
# 1. Set passphrase to true to be prompted each time
branch = "main" # Branch of remote resource repository
# URL of remote resource repository, leave it empty to use the default URL
url = "git@github.com:MaaAssistantArknights/MaaResource.git"
# If you want to use ssh, a certificate is needed which can be "ssh-agent" or "ssh-key"
# To use ssh-agent, set `use_ssh_agent` to true, and leave `ssh_key` and `passphrase` empty
# use_ssh_agent = true # Use ssh-agent to authenticate
# To use ssh-key, set `ssh_key` to path of ssh key,
ssh_key = "~/.ssh/id_ed25519" # Path of ssh key
# A Passphrase is needed if the ssh key is encrypted
passphrase = "password" # Passphrase of ssh key
# Store plain text password in configuration file is unsafe, so there are some ways to avoid it
# 1. set `passphrase` to true, then maa-cli will prompt you to input passphrase each time
# passphrase = true
# 2. Use an environment variable
# 2. set `passphrase` to a environment variable, then maa-cli will use the environment variable as passphrase
# passphrase = { env = "MAA_SSH_PASSPHRASE" }
# 3. Use a command output (useful with password managers)
# 3. set `passphrase` to a command, then maa-cli will execute the command to get passphrase
# which is useful when you use a password manager to manage your passphrase
# passphrase = { cmd = ["pass", "show", "ssh/id_ed25519"] }
```
**NOTE**:
- The `Alpha` channel for MaaCore is only available on Windows
- Hot update resources require the basic resources installed with MaaCore
- Using the `git` backend requires the `git` command to be available
- SSH authentication requires either `ssh_key` configuration or `ssh-agent`
- The `resource.remote.url` only affects first installation; to change it later, modify it manually or delete and reinstall resources. Get the repository location with `maa dir hot-update`.
- The `Alpha` channel of MaaCore is only available on Windows;
- The hot update resource can not work separately, it should be used with basic resources installed with MaaCore;
- If you want to use `git` backend, `git` command is required;
- If you want to fetch resources with ssh, the `ssh_key` is required;
- The `resource.remote.url` only affects first-time installation, it will be ignored when updating resource. If you want to change the remote URL, you should change it manually or delete the resource directory and reinstall the resources. The directory of the repository can be located by `maa dir hot-update`.
## Example Configuration Files
## Example of config file
- [Example configurations][example-config]
- [Maintainer's configuration][wangl-cc-dotfiles]
- [Example configuration][example-config];
- [Configuration used by maintainer][wangl-cc-dotfiles].
## JSON Schema
## JSON schema
JSON schemas for configuration files are in the [`schemas` directory][schema-dir]:
The JSON schema of configuration files can be found at [`schemas` directory][schema-dir]:
- Task configuration schema: [`task.schema.json`][task-schema]
- MaaCore configuration schema: [`asst.schema.json`][asst-schema]
- CLI configuration schema: [`cli.schema.json`][cli-schema]
- The schema of the task configuration is [`task.schema.json`][task-schema];
- the schema of the MaaCore configuration file is [`asst.schema.json`][asst-schema];
- the schema of the CLI configuration file is [`cli.schema.json`][cli-schema].
With these schemas, you can get auto-completion and validation in supported editors with plugins.
With the help of JSON schema, you can get auto-completion and validation in some editors with plugins.
[task-types]: ../../protocol/integration.md#list-of-task-types
[emulator-ports]: ../../manual/connection.md#obtain-port-number
[playcover-doc]: ../../manual/device/macos.md#%E2%9C%85-playcover-the-software-runs-most-fluently-for-its-nativity-%F0%9F%9A%80
[waydroid-doc]: https://github.com/MaaAssistantArknights/maa-cli/blob/main/crates/maa-cli/manual/device/linux.md#✅-waydroid
[example-config]: https://github.com/MaaAssistantArknights/maa-cli/blob/main/crates/maa-cli/config_examples
[wangl-cc-dotfiles]: https://github.com/wangl-cc/dotfiles/tree/main/home/dot_config/maa
[wangl-cc-dotfiles]: https://github.com/wangl-cc/dotfiles/tree/master/.config/maa
[schema-dir]: https://github.com/MaaAssistantArknights/maa-cli/blob/main/crates/maa-cli/schemas/
[task-schema]: https://github.com/MaaAssistantArknights/maa-cli/blob/main/crates/maa-cli/schemas/task.schema.json
[asst-schema]: https://github.com/MaaAssistantArknights/maa-cli/blob/main/crates/maa-cli/schemas/asst.schema.json

View File

@@ -7,7 +7,7 @@ icon: ph:question-fill
## 1. How to use `$HOME/.config/maa` as the configuration directory on macOS?
Due to the Rust library [Directories](https://github.com/dirs-dev/directories-rs/) using Apple-style directories on macOS by default, maa-cli also uses Apple-style configuration directories by default. However, XDG-style directories are more suitable for command-line programs. If you want to use XDG-style directories, you can set the `XDG_CONFIG_HOME` environment variable, such as `export XDG_CONFIG_HOME="$HOME/.config"`, which will make maa-cli use XDG-style configuration directories. If you want to use XDG-style configuration directories but don't want to set environment variables, you can use the following command to create a symbolic link:
Due to the limitation of [Directories](https://github.com/dirs-dev/directories-rs/), maa-cli uses the Apple-style configuration directory on macOS by default. However, the XDG-style configuration directory is more suitable for command-line programs. If you want to use the XDG style configuration directory, you can set the `XDG_CONFIG_HOME` environment variable, such as `export XDG_CONFIG_HOME="$HOME/.config"`, this will make maa-cli use the XDG style configuration directory. Or you can use the below command to create a symbolic link:
```bash
mkdir -p "$HOME/.config/maa"

View File

@@ -47,7 +47,7 @@ Homebrew users can install maa-cli via the unofficial [tap](https://github.com/M
nix run github:Cryolitia/nur-packages#maa-cli-nightly
```
Stable is packaged in [nixpkgs](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-cli/package.nix), using the nixpkgs Rust toolchain; Nightly is in [NUR](https://github.com/Cryolitia/nur-packages/blob/master/pkgs/maa-assistant-arknights/maa-cli.nix), using the Beta Channel Rust toolchain, automatically updated and built daily by GitHub Actions.
Stable is the maa-cli packaged in [nixpkgs](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-cli/package.nix), using the nixpkgs's Rust toolchain; Nightly is in [NUR](https://github.com/Cryolitia/nur-packages/blob/master/pkgs/maa-assistant-arknights/maa-cli.nix), uses the Beta Channel of Rust toolchain, automatically updates and builds for verification by Github Action daily.
- Users using Homebrew on Linux please refer to the macOS installation method above.
@@ -96,14 +96,6 @@ maa-cli only provides an interface for MaaCore, it needs MaaCore and resources t
maa install
```
For Windows platform users, before running the `maa install` command, please run the following command as administrator in Command Prompt or PowerShell to install the required VC++ toolset:
- Windows:
```bat
winget install "Microsoft.VCRedist.2015+.x64" --override "/repair /passive /norestart" --uninstall-previous --accept-package-agreements --force
```
For users who installed via package managers, MaaCore can also be installed via package managers:
- Homebrew

View File

@@ -5,98 +5,96 @@ icon: material-symbols:summarize
# Usage
maa-cli's main functionality is to automate Arknights game tasks by calling MaaCore. Additionally, for convenience, maa-cli also provides functions to manage MaaCore.
maa-cli is a command-line interface for MaaCore that automates tasks in the game Arknights. Additionally, maa-cli can manage MaaCore.
## Manage MaaCore
maa-cli can install and update MaaCore and resources by running the following commands:
maa-cli can install and update MaaCore and resources, just run the following commands:
```bash
maa install # Install MaaCore and resources
maa update # Update MaaCore and resources
```
## Update maa-cli Itself
## Update maa-cli itself
maa-cli can update itself by running the following command:
maa-cli can update itself, just run the following command:
```bash
maa self update
```
**Note**: Users who installed maa-cli via a package manager should use the package manager to update maa-cli. This command will not work for those users.
**Note**: Users who install maa-cli via a package manager should use the package manager to update maa-cli, this command is invalid for these users.
## Initialize Configuration
Once MaaCore is installed, you can typically run tasks directly without additional configuration. However, the default configuration may not be suitable for all users, so you can initialize the configuration with:
Once MaaCore is installed, you can run tasks directly without additional configuration. The default configuration may not be suitable for all users. Therefore, you can initialize the configuration by running the following command:
```bash
maa init
```
With this command, you can interactively configure [MaaCore-related settings][config-core].
With this command, you can configure [the relevant configurations of MaaCore][config-core] interactively.
## Run Tasks
After installing and configuring MaaCore, you can run tasks. maa-cli supports two types of tasks: predefined tasks and custom tasks.
### Predefined Tasks
### Predefined tasks
For common tasks, maa-cli provides several predefined options:
- `maa startup [client]`: start the game client and enter the main screen, the `client` is the client type of game, leave it empty to don't start the game.
- `maa closedown [client]`: close the game client, the `client` is the client type of game, default is `Official`.
- `maa fight [stage]`: run a "fight" task, the `stage` is the stage to fight, like `1-7`, `CE-6`, etc.; if not given, the user will be prompted to input one.
- `maa copilot <maa_uri>...`: run a "copilot" task, the `maa_uri` is the URI of a copilot task, multiple URIs will be executed in sequence, `maa_uri` can be `maa://1234` or local file path `./1234.json`.
- `maa sscopilot <maa_uri>`: run a "sscopilot" task, the `maa_uri` is the URI of a sscopilot task.
- `maa roguelike [theme]`: run a "roguelike" task, the `theme` is the theme of roguelike, and available themes are `Phantom`, `Mizuki`, `Sami` and `Sarkaz`.
- `maa reclamation [theme]`: run a "reclamation" task, the `theme` is the theme of reclamation, and available themes are `Tales`.
- `maa startup [client]`: Start the game and enter the main interface. `[client]` is the client type; leave empty to not start any game client.
- `maa closedown [client]`: Close the game client. `[client]` is the client type, defaulting to `Official`.
- `maa fight [stage]`: Run a combat task. `[stage]` is the stage name like `1-7`; leave empty to select the last or current stage.
- `maa copilot <maa_uri>...`: Auto-run copilot tasks. `<maa_uri>` is the task URI, multiple URIs will execute in sequence. `maa_uri` can be `maa://1234` or a local file path like `./1234.json`.
- `maa sscopilot <maa_uri>`: Auto-run Stationary Security Service tasks. `<maa_uri>` is the task URI.
- `maa roguelike <theme>`: Auto-run Integrated Strategy. `<theme>` is the theme, with options including `Phantom`, `Mizuki`, `Sami`, `Sarkaz`, and `JieGarden`.
- `maa reclamation <theme>`: Auto-run Reclamation Algorithm. `<theme>` is the theme, currently only `Tales` is available.
The above tasks accept some parameters, you can view the specific parameters by `maa <task> --help`.
These tasks accept various parameters. You can view the specific parameters with `maa <task> --help`.
For example, if you want to open the game, use 3 sanity potions to farm BB-7, and then close the game, you can run:
For example, if you want to open the game, use 3 sanity medicines to farm BB-7, and then close the game, you can run the following command:
```bash
maa startup Official && maa fight BB-7 -m 3 && maa closedown
maa startup YoStarEN && maa fight BB-7 -m 3 && maa closedown
```
### Custom Tasks
Due to MAA's support for numerous tasks, maa-cli cannot provide predefined options for everything. Additionally, you may need to run multiple tasks as in the example above. To address this, maa-cli offers custom task functionality. Custom tasks can combine different tasks, providing finer control over parameters and execution order. They also support conditional execution based on specific criteria, automating your daily routines. Custom tasks are defined via configuration files—see the [Custom Task Documentation][custom-task] for details on location and format. After creating a configuration file, run your custom task with `maa run <task>`, where `<task>` is the filename without extension.
Due to the multitude of tasks supported by MAA, maa-cli cannot provide predefined options for all tasks. Additionally, you may need to run multiple tasks as shown in the example above. To address this issue, maa-cli offers custom task functionality. Custom tasks allow for the combination of different tasks and provide finer control over the parameters of each task as well as the execution order. Furthermore, custom tasks support conditional statements, enabling you to decide whether to execute a task based on certain conditions or to execute a task with specific parameters. This can be used to automate your daily tasks. A custom task is defined in a configuration file. The location and format of the configuration file are described in the [Custom Task Document][custom-task]. After defining the configuration file, you can run the custom task by `maa run <task>`, where `<task>` is the name of the custom task, excluding the extension.
### Task Summary
Both predefined and custom tasks output summary information upon completion, including each subtask's runtime (start time, end time, duration). For certain tasks, result summaries include:
maa-cli will output a summary of the task after the task is terminated, including the running time of each subtask (start time, end time, running time). For some tasks, it will also output a summary of the task results:
- `fight` task: Stage name, number of runs, sanity potions used, and drop statistics
- `infrast`: Operators assigned to each facility, including product types for factories and trading posts
- `recruit`: Tags, star ratings, and status for each recruitment, plus total recruitment count
- `roguelike`: Exploration count, investment count
- `fight` task: stage name, times, sanity cost, and drop statistics;
- `infrast`: operators stationed in each facility, for the factory and trading post, it also includes the type of product;
- `recruit`: tags, star ratings, and status of each recruitment, as well as the total number of recruitments;
- `roguelike`: exploration times, investment times.
If you don't want task summaries, disable them with the `--no-summary` parameter.
If you don't want the task summary, you can turn it off by `--no-summary`.
### Task Logging
### Loggings
maa-cli outputs logs with the following levels (low to high): `Error`, `Warn`, `Info`, `Debug`, and `Trace`. The default level is `Warn`. Set the log level via the `MAA_LOG` environment variable (e.g., `MAA_LOG=debug`) or use `-v` to increase and `-q` to decrease the level.
maa-cli will output logs, the log output levels from low to high are `Error`, `Warn`, `Info`, `Debug`, and `Trace`. The default log output level is `Warn`. The log level can be set by the `MAA_LOG` environment variable, for example, `MAA_LOG=debug`. You can also increase or decrease the log output level by `-v` or `-q`.
By default, logs go to standard error (stderr). The `--log-file` option can redirect logs to a file at `$(maa dir log)/YYYY/MM/DD/HH:MM:SS.log`, where `$(maa dir log)` is the log directory obtainable via `maa dir log`. You can also specify a custom log path with `--log-file=path/to/log`.
maa-cli will output logs to stderr by default. The `--log-file` option can output logs to a file, the logs are saved in `$(maa dir log)/YYYY/MM/DD/HH:MM:SS.log`, where `$(maa dir log)` is the log directory, you can get it by `maa dir log`. You can also specify the log file path by `--log-file=path/to/log`.
All logs normally include a timestamp and level prefix. The `MAA_LOG_PREFIX` environment variable controls this behavior: `Always` always includes prefixes, `Auto` includes prefixes in log files but not in stderr output, and `Never` omits prefixes even in log files.
By default, all output logs will include a timestamp and a log-level prefix. You can change this behavior by the `MAA_LOG_PREFIX` environment variable. When set to `Always`, the prefix will always be included, when set to `Auto`, the prefix will be included when writing to the log file, and not included when writing to stderr, and when set to `Never`, the prefix will not be included even when writing to the log file.
### Other Subcommands
### Other subcommands
Besides the above commands, maa-cli provides additional subcommands:
Except for the above subcommands, maa-cli also provides other subcommands:
- `maa list`: List all available tasks
- `maa dir <dir>`: Get a specific directory path, such as `maa dir config` for the configuration directory
- `maa version`: Get version information for `maa-cli` and `MaaCore`
- `maa convert <input> [output]`: Convert between `JSON`, `YAML`, or `TOML` format files
- `maa complete <shell>`: Generate auto-completion scripts
- `maa activity [client]`: Get current in-game activity information, with `[client]` defaulting to `Official`
- `maa cleanup`: Clean `maa-cli` and `MaaCore` caches
- `maa import <file> [-t <type>]`: Import a configuration file, with `-t` specifying the type (e.g., `cli`, `profile`, `infrast`)
- `maa list`: list all available tasks;
- `maa dir <dir>`: get the path of a specific directory, for example, `maa dir config` can be used to get the path of the configuration directory;
- `maa version`: get the version information of `maa-cli` and `MaaCore`;
- `maa convert <input> [output]`: convert a file in `JSON`, `YAML`, or `TOML` format to another format;
- `maa complete <shell>`: generate an auto-completion script;
- `maa activity [client]`: get the current activity information of the game, the `client` is the client type, default is `Official`.
- `maa cleanup`: clean up the cache of `maa-cli` and `MaaCore`.
- `maa import <file> [-t <type>]`: import a configuration file, the `file` is the path of the configuration file. The `-t` option can specify the type of the configuration file, such as `cli`, `profile`, `infrast`, etc.
For more command information, use `maa help`. For specific command details, use `maa help <command>`.
More command usage can be viewed by `maa help`, and the usage of specific commands can be viewed by `maa help <command>`.
[config-core]: config.md#maacore-related-configurations
[custom-task]: config.md#custom-tasks

View File

@@ -3,247 +3,192 @@ order: 3
icon: mdi:plug
---
# Connection Settings
# Connection
## Auto Detection
## Automatic Detection
MAA can automatically detect and fill in the ADB path, connection address, and connection configuration for a **single currently running emulator**.
MAA can automatically detect and fill in the ADB path, connection address, and connection present through the **currently running single emulator**.
As of MAA v5.22.3, the following emulators and connection addresses are supported for detection:
As of MAA v5.7.0, the supported emulators and connection addresses for detection are as follows:
- BlueStacks 5: `127.0.0.1:5555/5556/5565/5575/5585/5595/5554`
- MuMu Player: `127.0.0.1:16384/16416/16448/16480/16512/16544/16576`
- MuMu Player 12: `127.0.0.1:16384/16416/16448/16480/16512/16544/16576`
- LDPlayer 9: `emulator-5554/5556/5558/5560`, `127.0.0.1:5555/5557/5559/5561`
- NoxPlayer: `127.0.0.1:62001/59865`
- MEmu Play: `127.0.0.1:21503`
- Memu Play: `127.0.0.1:21503`
If detection fails, try launching MAA with UAC administrator privileges and detect again. If it still fails, refer to the manual setup instructions below and verify that your emulator and connection address are included in the list above.
If detection fails, try launching MAA with UAC administrator privileges and retry detection. If it still fails, please refer to the manual setup below and verify whether the emulator and connection address are included in the list above.
## ADB Path
:::info Technical details
Auto detection uses the emulator's ADB. Manual configuration is only required if auto detection fails.
`Force Replace ADB` will download Google's ADB and use it automatically.
If ADB is available in the environment variables, just fill in `adb`.
:::info Technical Details
Automatic detection uses the emulator's ADB, but sometimes problems occur with automatic detection, then manual settings are required.
`Replace ADB` is to download the ADB provided by Google and then replace it. If you set up Google's ADB yourself, you can do it once and for all.
:::
### Use emulator's ADB
### Use the ADB provided by the emulator
Go to your emulator's installation directory. On Windows, you can right-click the process in Task Manager while the emulator is running and select `Open file location`.
Go to the emulator installation path. In Windows, when the emulator is running, right-click the process in the Task Manager and click `Open the location of the file`.
Look for an exe file with `adb` in its name in the top-level or subdirectories. You can use search to find it.
There should be an exe file with `adb` in its name in the top-level or lower directory. You can search and select it.
:::details Examples
`adb.exe` `HD-adb.exe` `adb_server.exe` `nox_adb.exe`
:::
### Use Google's ADB
### Use ADB provided by Google
[Download here](https://dl.google.com/android/repository/platform-tools-latest-windows.zip), extract it, and select `adb.exe`.
[Click](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) to download and unzip, then select `adb.exe`.
We recommend extracting it directly to the MAA folder so you can enter `.\platform-tools\adb.exe` as the ADB path, allowing it to move with the MAA folder.
We are recommended to extract it directly to the MAA folder, so that you can directly fill in `.\platform-tools\adb.exe` in the ADB path, and move it with MAA.
## Connection Address
::: tip
Emulators running on your local machine should use addresses like `127.0.0.1:<port number>` or `emulator-<four digits>`.
The connection address of the emulator running on this computer should be `127.0.0.1:<port>` `emulator-<four numbers>`
:::
### Emulator documentation and reference addresses
### Emulator documents and addressess for reference
- [Bluestacks 5](https://support.bluestacks.com/hc/en-us/articles/360061342631-How-to-transfer-your-apps-from-BlueStacks-4-to-BlueStacks-5): Emulator settings show current multi-instance ports.
- [MuMu Player](https://mumu.163.com/help/20240807/40912_1073151.html?maa): Multi-instance manager shows running ports in the top-right corner.
:::warning
The following links are Chinese websites, cuz no English websites were found. Maybe.
:::
- [Bluestacks 5](https://support.bluestacks.com/hc/zh-tw/articles/360061342631-%E5%A6%82%E4%BD%95%E5%B0%87%E6%82%A8%E7%9A%84%E6%87%89%E7%94%A8%E5%BE%9EBlueStacks-4%E8%BD%89%E7%A7%BB%E5%88%B0BlueStacks-5#%E2%80%9C2%E2%80%9D) `127.0.0.1:5555`
- [MuMu Player Pro](https://mumu.163.com/mac/function/20240126/40028_1134600.html) `127.0.0.1:16384`
- [LDPlayer 9](https://help.ldmnq.com/docs/LD9adbserver) `emulator-5554`
- [MuMu Player 12](https://mumu.163.com/help/20230214/35047_1073151.html) `127.0.0.1:16384`
- [LD Player 9](https://help.ldmnq.com/docs/LD9adbserver) `emulator-5554`
- [NoxPlayer](https://support.yeshen.com/zh-CN/qt/ml) `127.0.0.1:62001`
- [MEmu Play](https://bbs.xyaz.cn/forum.php?mod=viewthread&tid=365537) `127.0.0.1:21503`
- [Memu Play](https://bbs.xyaz.cn/forum.php?mod=viewthread&tid=365537) `127.0.0.1:21503`
For other emulators, refer to [Zhao Qingqing's blog](https://www.cnblogs.com/zhaoqingqing/p/15238464.html).
For other emulators, please check [Zhao Qingqing's blog](https://www.cnblogs.com/zhaoqingqing/p/15238464.html).
::: details Alternative methods
### Obtain Port Number
- Method 1: Check emulator ports using ADB commands
- MuMu 12: The running emulator ports can be found in the upper right corner of the MultiPlayer.
- Bluestacks 5: The current emulator ports can be viewed in the emulator settings.
- _TODO_
1. Launch **one** emulator and ensure no other Android devices are connected to your computer.
2. Open a terminal in the folder containing the ADB executable.
3. Run the following command:
::: details Alternatives
- Method 1: Use the adb command to view the running port directly
1. Launch **one** emulator and make sure no other Android devices are connected to this computer.
2. Launch a terminal in the folder where the adb executable is.
3. Execute the following command.
```sh
# Windows command prompt
# Windows CMD
adb devices
# Windows PowerShell
.\adb devices
```
Example output:
An example of output:
```text
List of devices attached
127.0.0.1:<port number> device
emulator-<four digits> device
127.0.0.1:<port> device
emulator-<four numbers> device
```
Use `127.0.0.1:<port>` or `emulator-<four digits>` as your connection address.
Use `127.0.0.1:<port>` or `emulator-<four numbers>` as the connection address.
- Method 2: Find established ADB connections
- Method 2: Find established adb connections
1. Follow Method 1.
2. Press `Windows key+S` to open search, type `Resource Monitor` and open it.
3. Go to the `Network` tab and find the emulator process name in the `Listening Ports` name column, such as `HD-Player.exe`.
4. Note all listening ports for the emulator process.
5. In the `TCP Connections` name column, find `adb.exe` and identify the remote port matching the emulator's listening port - this is the emulator's debug port.
1. Do method 1.
2. Press `Win+S` to open the search bar, type `Resource Monitor` and open it.
3. Switch to the `Network` tab and look for the emulator process name in the name column of `Listening Port`, such as `HD-Player.exe`.
4. Make a note of all listening ports for the emulator process.
5. Find `adb.exe` in the name column of `TCP connection`. The port in the remote port column that is consistent with the emulator listening port is the emulator debugging port.
:::
### BlueStacks with Hyper-V port changes on every startup
### Automatically Start Multiple Emulators
In `Connection Settings`, set `Connection Configuration` to `BlueStacks`, then check both `Auto Detect Connection` and `Re-detect Each Time`.
- If you need to operate multiple emulators simultaneously, you can copy the MAA folder multiple times, and use **different MAAs**, **the same adb.exe**, and **different connection addresses** to connect.
- Taking `BlueStacks International Version` as an example, two ways to start multiple emulators are introduced.
This should work in most cases. If connection still fails, you may have multiple emulator cores or issues requiring additional settings as explained below.
- Perform multiple operations by attaching commands to `HD-Player.exe`.
#### Specifying `Bluestacks.Config.Keyword`
1. Start the corresponding emulator separately.
2. Open the Task Manager, find the corresponding emulator process, go to the Details tab, right-click the column above, click `Select Columns`, and check `Command Line`.
3. In the newly added `Command Line` column, find the content after `"...\Bluestacks_nxt\HD-Player.exe"`.
4. Fill in the found content, similar to `--instance Nougat32`, in `Startup Settings` - `Additional Commands`.
::: info Note
If you're using multi-instance or have multiple emulator cores installed, you'll need additional settings to specify which emulator number to use
Note: After the operation is completed, it is recommended to hide the `Command Line` column opened in `Step 2` to prevent freezing.
- Example:
```bash
Multi-instance 1:
Emulator Path: C:\Program Files\BlueStacks_nxt\HD-Player.exe
Additional Commands: --instance Nougat32 --cmd launchApp --package "com.hypergryph.arknights"
Multi-instance 2:
Emulator Path: C:\Program Files\BlueStacks_nxt\HD-Player.exe
Additional Commands: --instance Nougat32_1 --cmd launchApp --package "com.hypergryph.arknights.bilibili"
```
The `--cmd launchApp --package` part starts and automatically runs the specified package name application after startup, which can be changed as needed.
- Perform multi-instance operation by using the shortcut of emulators or apps.
1. Open the multi-instance manager and add the corresponding emulator's shortcut.
2. Fill in the path of the emulator shortcut in `Startup Settings` - `Emulator Path`.
Note: Some emulators support creating app shortcuts, which can directly launch the emulator and open Arknights with the app shortcut.
- Example:
```bash
Multi-instance 1:
Emulator Path: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\BlueStacks\Multi-instance 1.lnk
Multi-instance 2:
Emulator Path: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\BlueStacks\Multi-instance 2 - Arknights.lnk
```
If using `Emulator Path` for multi-instance operation, it is recommended to leave `Additional Commands` in `Startup Settings` empty.
### The port number of BlueStack emulator Hyper-V is different every time it is started
:::warning
TODO: replace these Chinese emulators links with English ones
:::
In `.\config\gui.json`, search for the `Bluestacks.Config.Keyword` field containing `"bst.instance.<emulator number>.status.adb_port"`. Find the emulator number in the `BlueStacks_nxt\Engine` folder in the emulator path.
## Connection Present
::: details Examples
Nougat64 core:
You need to select the configuration of the emulator you are using. If it is not in the list, select General Mode. If General Mode is not available please try and select any of the other available presents.
```json
"Bluestacks.Config.Keyword":"bst.instance.Nougat64.status.adb_port",
```
Pie64_2 core: (the number after the core name indicates a multi-instance core)
```json
"Bluestacks.Config.Keyword": "bst.instance.Pie64_2.status.adb_port",
```
:::
#### Specifying `Bluestacks.Config.Path`
::: info Note
MAA now attempts to read the `bluestacks.conf` storage location from the registry. When this fails, you need to manually specify the configuration file path
:::
1. Find the `bluestacks.conf` file in the BlueStacks data directory
- International version default: `C:\ProgramData\BlueStacks_nxt\bluestacks.conf`
- Chinese version default: `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf`
2. If this is your first time, run MAA once so it automatically generates the configuration file.
3. **First close** MAA, **then** open `gui.json`, find your current configuration name under `Configurations` (viewable in Settings-Switch Configuration, default is `Default`), search for the `Bluestacks.Config.Path` field, and enter the full path to `bluestacks.conf`. (Note: use escaped backslashes `\\`)
::: details Example
For `C:\ProgramData\BlueStacks_nxt\bluestacks.conf`:
```json
{
"Configurations": {
"Default": {
"Bluestacks.Config.Path": "C:\\ProgramData\\BlueStacks_nxt\\bluestacks.conf"
// Other configuration fields, don't manually modify
}
}
}
```
:::
## Connection Configuration
Select the configuration matching your emulator. If not listed, choose General Configuration. If that doesn't work, try any other available configuration.
For specific differences, see the [source code](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/dev/resource/config.json#L65).
For specific differences, you can read the [source code](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/dev/resource/config.json#L65).
### MuMu Screenshot Enhanced Mode
Requires official or Arknights-specific MuMu V4.1.26 or newer. <!-- Official V3.8.13 supports initial enhanced screenshots -->
Only Chinese or Arknights Edition MuMu 12 V4.0.0 and later versions are supported. Global Edition is not supported at this time. <!-- Chinese V3.8.13 -->
1. In `Settings` - `Connection Settings`, check `Enable MuMu Screenshot Enhanced Mode`. MAA will automatically try to get the installation path from the registry when you check this option.
1. SettingsConnection Settings, enable `Enable MuMu's screenshot enhancement mode`. MAA will attempt to automatically fill in the exec path through the registry when the switch is checked.
2. Enter the path to the `MuMu Player` or `MuMuPlayerGlobal-12.0` or `YXArkNights-12.0` folder in `MuMu Installation Path`, e.g., `C:\Program Files\Netease\MuMu Player`.
2. `MuMu12 Emulator exec path` Fill in the path to the `MuMuPlayer-12.0` or `YXArkNights-12.0` folder. e.g. `C:\Program Files\Netease\MuMuPlayer-12.0`.
3. If using MuMu Network Bridge, check `MuMu Network Bridge Mode` and manually enter the number of the corresponding emulator in the MuMu multi-instance manager, such as `0` for the main instance.
3. If using MuMu network bridging, check `MuMu network bridging mode` and manually enter the serial number of the corresponding emulator in MuMu Multi-Instance Manager, such as `0` for the main instance.
### LD Screenshot Enhanced Mode
Requires official or international LDPlayer 9 V9.1.32 or newer. <!-- Official V9.0.78 supports initial enhanced screenshots but has high-resolution issues that V9.1.29 fixes -->
Only Chinese or Global LD Player 9 V9.1.32 and later versions are supported. <!-- Chinese V9.0.78 -->
1. In `Settings` - `Connection Settings`, check `Enable LD Screenshot Enhanced Mode`. MAA will automatically try to get the installation path from the registry when you check this option.
1. SettingsConnection Settings, enable `Enable LD's screenshot enhancement mode`. MAA will attempt to automatically fill in the exec path through the registry when the switch is checked.
2. Enter the path to the `LDPlayer9` folder in `LD Installation Path`, e.g., `C:\leidian\LDPlayer9\`.
2. `LD Emulator exec path` Fill in the path to the `LDPlayer9` folder. e.g. `C:\leidian\LDPlayer9\`
3. Enter the number (ID) of the corresponding emulator in the LDPlayer multi-instance manager in `Instance Number`, such as `0` for the main instance.
3. `Instance Number` Fill in the serial number (ID) of the corresponding emulator in LD Multiplayer. e.g. `0` for Main Multiplayer.
## Touch Mode
1. [Minitouch](https://github.com/DeviceFarmer/minitouch): An Android touch event handler written in C that operates on `evdev` devices and provides a Socket interface for external programs to trigger touch events and gestures. Starting with Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode.<sup>[source](https://github.com/DeviceFarmer/minitouch?tab=readme-ov-file#for-android-10-and-up)</sup>
2. [MaaTouch](https://github.com/MaaAssistantArknights/MaaTouch): MAA's Java reimplementation of Minitouch that uses Android's native `InputDevice` and adds extra features. Compatibility with newer Android versions is still being tested. ~~Help us test it~~
3. Adb Input: Directly calls ADB to use Android's `input` command for touch operations. Most compatible but slowest.
1. [Minitouch](https://github.com/DeviceFarmer/minitouch)An Android touch eventer written in C uses `evdev` to provide a Socket interface for external programs to trigger touch events and gestures. Starting with Android 10, Minitouch no longer works when SELinux is `Enforcing`.<sup>[Source](https://github.com/DeviceFarmer/minitouch?tab=readme-ov-file#for-android-10-and-up)</sup>
2. [MaaTouch](https://github.com/MaaAssistantArknights/MaaTouch)A Java-based reimplementation of Minitouch by MAA, which uses Android's `InputDevice`, and added additional features. Availability of higher versions of Android is yet to be tested. ~~Help us do some testing~~
3. Adb InputDirectly call ADB to use Android's `input` command to perform touch operations. It has the highest compatibility and the slowest speed.
## ADB Lite
MAA's independent ADB Client implementation that communicates directly with the ADB Server via TCP. Compared to the original ADB, it avoids constantly launching multiple ADB processes, reducing performance overhead, but some screenshot methods aren't available.<sup>[PR](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/3315)</sup>
An ADB Client independently implemented by MAA uses TCP to communicate directly with the ADB Server. Compared with the original ADB, it can avoid opening multiple ADB processes continuously and reduce performance overhead, but some screenshot methods are unavailable.<sup>[PR](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/3315)</sup>
We recommend enabling it, but specific pros and cons need feedback. ~~Help us test it x2~~
## Running multiple MAA and emulator instances
::: info How to do it
To operate multiple emulators simultaneously, copy the MAA folder multiple times and use **different MAA instances**, **the same adb.exe**, and **different connection addresses** to connect.
:::
### Auto-starting multiple emulator instances
Using [BlueStacks International](./device/windows.md) as an example, here are two ways to auto-start multiple emulator instances:
#### Start via additional commands
1. Launch a single multi-instance emulator.
2. Open Task Manager, find the corresponding emulator process, go to the Details tab, right-click the column header, click `Select Columns`, and check `Command line`.
3. In the new `Command line` column, find the content after `...\Bluestacks_nxt\HD-Player.exe"`.
4. Add the content you found (similar to `--instance Nougat32`) to `Startup Settings` - `Additional Commands`.
::: note
After finishing, we recommend hiding the `Command line` column opened in `Step 2` to prevent slowdowns
:::
::: details Example
```text
Instance 1:
Emulator Path: C:\Program Files\BlueStacks_nxt\HD-Player.exe
Additional Commands: --instance Nougat32 --cmd launchApp --package "com.hypergryph.arknights"
Instance 2:
Emulator Path: C:\Program Files\BlueStacks_nxt\HD-Player.exe
Additional Commands: --instance Nougat32_1 --cmd launchApp --package "com.hypergryph.arknights.bilibili"
```
The `--cmd launchApp --package` part auto-launches the specified package after startup; modify as needed.
:::
#### Start via emulator shortcuts
Some emulators support creating application shortcuts that directly launch the emulator and open Arknights.
1. Open the multi-instance manager and create shortcuts for the corresponding emulators.
2. Enter the emulator shortcut path in `Startup Settings` - `Emulator Path`
::: details Example
```text
Instance 1:
Emulator Path: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\BlueStacks\Instance 1.lnk
Instance 2:
Emulator Path: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\BlueStacks\Instance 2-Arknights.lnk
```
:::
When using `Emulator Path` for multi-instance operation, we recommend leaving `Startup Settings` -
It is recommended to enable it, but the specific advantages and disadvantages need feedback. ~~Help us do some testing x2~~

View File

@@ -3,106 +3,107 @@ order: 4
icon: mingcute:android-fill
---
# Android Physical Devices
# Android Physical Device
::: warning
This method involves ADB command-line usage, has lower stability, and still requires computer connection. **Not recommended** for beginners.
This method involves ADB debugging and requires connection to a computer, it is **not recommended** for beginners.
:::
::: info Note
0. Please also refer to [Connection Settings](../connection.md).
1. Starting from Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode. Please switch to other touch modes, or **temporarily** switch SELinux to `Permissive` mode.
2. Due to the extreme complexity of the Android ecosystem, try changing the `Connection Configuration` in MAA `Settings` - `Connection Settings` to `General Mode`, `Compatibility Mode`, `2nd Resolution`, or `General Mode (Block Exception Output)` until one mode works properly.
3. Since MAA only supports `16:9` aspect ratios, devices with non-`16:9` or `9:16` screen ratios (including most modern devices) need to have their resolution forcibly changed. If your device's native screen ratio is `16:9` or `9:16`, you can skip the `Change Resolution` section.
4. Switch your device's navigation method to something other than `Full Screen Gestures`, such as `Classic Navigation Keys`, to avoid accidental operations.
5. Please set the `Notched Screen UI Adaptation` option in the game settings to 0 to avoid task errors.
0. Please also check [Connection](../connection.md).
1. Starting from Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode, please switch to other touch modes or switch SELinux **temporary** to `Permissive` mode.
2. Due to the extreme complexity of the Android ecosystem, try to change the `Connection Configuration` in MAA `Settings` - `Connection` to `General Mode` or `Compatibility Mode` or `2nd Resolution` or `General Mode (Blocked exception output)` until one of the modes is working properly.
3. Since MAA only supports `16:9` ratio resolutions, devices with non-`16:9` or `9:16` screen ratios will need to be forced to change their resolution, which includes most modern devices. If the connected device has a native `16:9` or `9:16` screen resolution ratio, you can skip the `Change resolution' section. 4.
4. Switch your device's navigation method to something other than `Full Screen Gestures`, such as the `Classic Navigation Keys` to avoid misuse.
5. Please adjust the `Shaped Screen UI Adaptation` section in the in-game settings to 0 to avoid task errors.
:::
::: tip
Typical `16:9` resolutions include `3840x2160` (4K), `2560x1440` (2K), `1920x1080` (1080P), and `1280x720` (720P).
Typical `16:9` ratio resolutions are `3840x2160` (4K), `2560x1440` (2K), `1920x1080` (1080P), `1280x720` (720P).
:::
## Download and Run ADB Debug Tool to Connect Device
## Download, run adb debugging tool and connect the device
1. Download [ADB](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) and extract it.
2. Open the extracted folder, clear the address bar, type `cmd`, and press Enter.
3. In the command prompt window that appears, type `adb`. If you see extensive help text, the command ran successfully.
4. Enable `USB Debugging` on your phone. The process varies by manufacturer, so use a search engine to find instructions. Manufacturers may provide additional USB debugging options, such as MIUI's `USB Installation` and `USB Debugging (Security Settings)` - enable these too.
5. Connect your phone to the computer with a data cable and enter the following command in the command prompt:
1. Download [adb](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) and unzip it.
2. Open the extracted folder, clear the address bar and type `cmd` and enter. 3.
3. Type `adb` in the command prompt window that pops up, if it gives you a lot of help text in English, it will run successfully.
4. Turn on `USB debugging` on your mobile phone, this may be different for each brand of mobile phone, so please use a search engine. Manufacturers may provide additional options for USB debugging, such as `USB Installation` and `USB Debugging (Security Settings)` in MIUI, please enable them at the same time.
5. Connect your phone to your computer via data cable and enter the following command in the command prompt window you just got.
```bash
adb devices
```
- When executed successfully, it will show connected USB debugging devices.
- If executed successfully, it will give you a message that the ``USB debugging`` device is connected.
- Example of a successful connection:
```bash
List of devices attached
VFNDU1682100xxxx device
VFNDU1682100xxxx device
```
- **The alphanumeric combination before `device` is the device serial number, which is also your MAA `Connection Address`.**
- **The alphanumeric combination in front of `device` is the serial number of the device, which also serves as the `connection address` of the MAA.**
- Modern Android devices require authorization on the device itself. Without authorization, you'll see:
- For modern Android devices to perform `USB debugging`, you need to click the pop-up window on the debugged device to authorise it, if not authorised, the example is as follows:
```bash
List of devices attached
VFNDU1682100xxxx unauthorized
VFNDU1682100xxxx unauthorized
Unauthorised
```
- If you consistently get "unauthorized" or "offline" status, restart both your device and computer. If that doesn't help, delete the `.android` folder in your user's personal directory and try again after restarting. Use search to find the exact location.
- If you are prompted for unauthorised or the serial number of the device shows `offline`, you need to reboot the device and computer and try again. If the problem is still not solved, you can delete the `.android` folder under the current user's personal folder and reboot again to retry, please search for the exact location.
## Change Resolution
## Change resolution
::: tip
Mobile screen resolution is specified as `short edge × long edge`, not `long edge × short edge` as with computer monitors. Determine the appropriate values for your specific device.
Mobile phone screen resolution is `short side*long side`, not `long side*short side` of computer monitor. Please determine the exact value according to your target device.
:::
- If you only have one device in your device list, run these commands to change/restore resolution:
- If there is only one device within the device list above, you can change/restore the resolution directly by running the following command.
```bash
# View current resolution
adb shell wm size
# Restore default resolution
# Restore the default resolution
adb shell wm size reset
# Change to 720p
# Change resolution to 720p
adb shell wm size 720x1280
# Change to 1080p
# Change resolution to 1080p
adb shell wm size 1080x1920
```
- If you have multiple devices, add the parameter `-s <target device serial number>` between `adb` and `shell`:
- If there are multiple devices, you need to add the parameter `-s <target device serial number>` between `adb` and `shell`, as shown in the following example.
```bash
# View current resolution
adb -s VFNDU1682100xxxx shell wm size
# Restore default resolution
# Restore the default resolution
adb -s VFNDU1682100xxxx shell wm size reset
# Change to 720p
# Change resolution to 720p
adb -s VFNDU1682100xxxx shell wm size 720x1280
# Change to 1080p
# Change resolution to 1080p
adb -s VFNDU1682100xxxx shell wm size 1080x1920
```
- Some apps with irregular designs may still have layout issues after resolution restoration. Usually, restarting the app or device resolves this.
- Some applications with irregular design may still have wrong layout after restoring the resolution, usually restarting the corresponding application or device can solve the problem.
::: danger Warning
Strongly recommended to restore the default resolution **before** restarting your device. Otherwise, depending on your device, unpredictable consequences may occur, ~~including layout chaos, touch misalignment, app crashes, inability to unlock, etc~~.
It is strongly recommended to restore the resolution **before** restarting the device next time, otherwise it may lead to unpredictable consequences depending on the device, ~~including but not limited to chaotic layout, touch misalignment, application flashback, unlocking, etc~~.
:::
## Automate Resolution Changes
## Automating resolution changes
1. Create two text files in the MAA directory with the following content:
1. Create two new text files in the MAA directory and fill them with the following contents.
```bash
# Adjust resolution to 1080p
adb -s <target device serial number> shell wm size 1080x1920
# Lower screen brightness (optional)
# Reduce screen brightness (optional)
adb -s <target device serial number> shell settings put system screen_brightness 1
```
@@ -111,69 +112,69 @@ Strongly recommended to restore the default resolution **before** restarting you
adb -s <target device serial number> shell wm size reset
# Increase screen brightness (optional)
adb -s <target device serial number> shell settings put system screen_brightness 20
# Return to home screen (optional)
# Return to desktop (optional)
adb -s <target device serial number> shell input keyevent 3
# Lock screen (optional)
adb -s <target device serial number> shell input keyevent 26
```
2. Rename the first file to `startup.bat` and the second to `finish.bat`.
2. Rename the first file to `startup.bat` and the second file to `finish.bat`.
- If no confirmation dialog appears when changing the extension and the file icon doesn't change, search for "How to show file extensions in Windows."
- If you don't see the double confirmation dialogue box for changing extension after renaming, and the file icon doesn't change, please search for "How to display file extensions in Windows".
3. In MAA's `Settings` - `Connection Settings`, set `Start Script` to `startup.bat` and `End Script` to `finish.bat`.
3. In `Settings` - `Connection` - `Starts with Script` and `Ends with Script` of MAA, fill in `startup.bat` and `finish.bat` respectively.
## Connect to MAA
## Connecting to MAA
### Wired Connection
### Wired connection
::: tip
Wired connections don't need IP addresses or ports - just the device serial number from `adb devices`.
A wired connection does not require any IP address or port, only the device serial number given by `adb devices`.
:::
1. Enter the target device serial number from above into MAA's `Settings` - `Connection Settings` - `Connection Address`.
1. Fill in the MAA `Settings` - `Connection` - `Connection address` with the serial number of the target device obtained above.
2. Link Start!
### Wireless Connection
- Ensure your device and computer are on the same network and can communicate with each other. Router settings like `AP Isolation` or `Guest Network` can block device communication - check your router documentation.
- Wireless debugging is disabled after device restart and must be re-enabled.
- Make sure that the device and the computer are on the same LAN and can communicate with each other. Settings such as `AP Isolation`, `Guest Network`, etc. can prevent communication between devices, please refer to the documentation of the corresponding router.
- Wireless debugging is disabled after a device reboot and needs to be reset.
#### Using `adb tcpip` for Wireless Debugging
#### To open a wireless port using `adb tcpip`
1. In the command prompt, enable wireless debugging:
1. Enable wireless debugging by entering the following command in the command prompt window you just opened.
```bash
adb tcpip 5555
# Add -s parameter to specify the serial number if multiple devices are connected
# Add the -s parameter to specify the serial number if multiple devices are present.
```
2. Find your device's IP address:
2. View the device IP address.
- Go to your phone's `Settings` - `Wi-Fi`, tap the connected network to view the IP address.
- The location varies by manufacturer - search for instructions if needed.
- Go to `Settings` - `WLAN` on your mobile phone and click on the currently connected wireless network to view the IP address.
- The IP address is different for different brands of devices, so please find it yourself.
3. Enter `<IP>:5555` in MAA's `Settings` - `Connection Settings` - `Connection Address`, e.g., `192.168.1.2:5555`.
3. Put `<IP>:5555` into MAA `Settings` - `Connection` - `Connection Address`, such as `192.168.1.2:5555`.
4. Link Start!
#### Using `adb pair` for Wireless Debugging
#### Use `adb pair` to open the wireless port
::: tip
`adb pair` wireless pairing (available in Android 11 and later via Developer Options) allows connection without a physical USB connection, unlike `adb tcpip`.
`adb pair` wireless pairing, i.e. connecting after pairing using `wireless debugging` in Developer Options on Android 11 and newer, avoids the need for a wired connection compared to `adb tcpip`.
:::
1. On your phone, go to Developer Options, tap `Wireless Debugging` and enable it. Tap `Pair device with pairing code` and keep the popup open until pairing completes.
1. Go to your phone's developer options, tap `Wireless debugging` and turn it on, tap OK, tap `Pair device using pairing code` and don't close the pop-up window that appears until pairing is complete. 2.
2. Complete the pairing:
2. To perform pairing.
1. In the command prompt, type `adb pair <IP address and port shown in the device popup>` and press Enter.
2. Enter the six-digit pairing code from the device popup and press Enter.
3. When you see `Successfully paired to <IP:port>`, the device popup will close automatically, and your computer's name will appear in the paired devices list.
1. At the command prompt, type `adb pair <IP address and port given in the device pop-up>` and enter.
2. Type `<six-digit pairing code given in the device pop-up window>` and enter.
3. The window appears with something like `Successfully paired to <IP:port>` and the pop-up window on the device disappears automatically, and the computer name appears at the bottom in the paired devices.
3. Enter the IP address and port shown on your device screen into MAA's `Settings` - `Connection Settings` - `Connection Address`, e.g., `192.168.1.2:11451`. **This is different from the address used for pairing**.
3. Put the `<IP address and port>` given on the current device's screen into MAA `Settings` - `Connection` - `Connection Address`, e.g. `192.168.1.2:11451`, **must be different from the one you have just put in**.
4. Link Start!
#### Using Root to Enable Wireless ADB
#### Enable the wireless port with root privileges
~~If you have access to root, why do you need to read this document~~

View File

@@ -3,146 +3,142 @@ order: 3
icon: teenyicons:linux-alt-solid
---
# Linux Emulators and Containers
# Linux Emulator and Container
## Preparation
Choose one of the following installation methods:
You can choose one of the following installation methods:
### Using maa-cli
### Use maa-cli
[maa-cli](https://github.com/MaaAssistantArknights/maa-cli) is a simple command-line tool for MAA written in Rust. Please read the [CLI User Guide](../cli/) for installation and usage instructions.
[maa-cli](https://github.com/MaaAssistantArknights/maa-cli) is a simple CLI for MAA made with Rust. Please read installation and usage tutorials in [User Guide for CLI](../cli/).
### Using Wine
### Use Wine
The MAA WPF GUI can currently be run through Wine.
The MAA WPF GUI can currently be run using Wine.
#### Installation Steps
1. Go to the [.NET download page](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) and download/install the Windows version of .NET **Desktop** Runtime.
1. Go to the [.NET Release Page](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) to download and install the .NET **Desktop** Runtime for Windows.
2. Download the Windows version of MAA, extract it, and run `wine MAA.exe`.
2. Download MAA for Windows, unzip it and run `wine MAA.exe`.
::: info Note
You need to set the ADB path to the [Windows version of `adb.exe`](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) in the connection settings.
You need to set the ADB path to [`adb.exe` for Windows](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) in the connection settings.
If you need to connect to USB devices via ADB, first run `adb start-server` outside of Wine to connect to the native ADB server through Wine.
If you need to connect to USB devices via ADB, please run `adb start-server` outside of Wine first, i.e. connect to the native ADB server via Wine.
:::
#### Using Linux Native MaaCore (Experimental)
#### Use Linux native MaaCore (experimental feature)
Download and build the [MAA Wine Bridge](https://github.com/MaaAssistantArknights/MaaAssistantArknights/tree/dev/src/MaaWineBridge) source code, replace the Windows version with the generated `MaaCore.dll` (ELF file), and place the Linux native dynamic libraries (`libMaaCore.so` and dependencies) in the same directory.
Download the [MAA Wine Bridge](https://github.com/MaaAssistantArknights/MaaAssistantArknights/tree/dev/src/MaaWineBridge) source and build it, replace the Windows version with the generated `MaaCore.dll` (ELF file) in the same directory as the Linux native dynamic libraries (`libMaaCore.so` and dependencies).
When running `MAA.exe` through Wine, it will load the Linux native libraries.
Running `MAA.exe` through Wine will load the Linux native libraries.
::: info Note
When using the Linux native MaaCore, you need to set the ADB path to the Linux native ADB in the connection settings.
To use Linux native MaaCore, you need to set the ADB path to Linux native ADB in the connection settings.
:::
#### Linux Desktop Integration (Experimental)
#### Linux Desktop Integration (experimental feature)
Desktop integration provides native desktop notification support and maps fontconfig font configurations to WPF.
Desktop integration provides native desktop notification support and the ability to map fontconfig font configurations to WPF.
Place the `MaaDesktopIntegration.so` generated by MAA Wine Bridge in the same directory as `MAA.exe` to enable this feature.
Enable it by placing `MaaDesktopIntegration.so` generated by MAA Wine Bridge in the same directory as `MAA.exe`.
#### Known Issues
- Wine DirectWrite forces hinting and doesn't pass DPI to FreeType, resulting in poor font display.
- When not using native desktop notifications, popup notifications grab the system-wide mouse focus, making it impossible to interact with other windows. You can mitigate this by enabling virtual desktop mode in `winecfg` or disabling desktop notifications.
- Wine-staging users need to disable the `Hide Wine version` option in `winecfg` for MAA to correctly detect the Wine environment.
- Wine's Light theme causes text color issues in WPF. We recommend using no theme (Windows Classic theme) in `winecfg`.
- Wine uses the old XEmbed tray icon system, which may not work properly under GNOME.
- When using Linux native MaaCore, automatic updates are not supported (~~the updater thinks: I should download a Windows version~~)
- Wine DirectWrite forces hinting to be enabled and does not pass DPI to FreeType, resulting in poor font display.
- When not using native desktop notifications, the popup notification will grab the system-wide mouse focus, making it impossible to operate other windows. This can be mitigated by enabling virtual desktop mode via `winecfg`, or disabling desktop notifications.
- Wine-staging users need to disable the `Hide Wine Version` option in `winecfg` in order for MAA to properly detect the Wine environment.
- Wine's Light theme causes some text colours in WPF to be abnormal, it is recommended to switch to no theme (Windows Classic theme) in `winecfg`.
- Wine uses the old XEmbed tray icon, which may not work properly under GNOME.
- Auto-update is not supported when using Linux native MaaCore (~~Updater: I think I should download a Windows version~~).
### Using Python
### Use Python
#### 1. Installing MAA Dynamic Library
#### 1. Installing dynamic library
1. Download and extract the Linux dynamic library from the [MAA website](https://maa.plus/), or install from a software repository:
1. Download and extract `Linux library` in [MAA Website](https://maa.plus/), or install from linux software repository:
- AUR: [maa-assistant-arknights](https://aur.archlinux.org/packages/maa-assistant-arknights), follow the post-installation instructions
- AUR[maa-assistant-arknights](https://aur.archlinux.org/packages/maa-assistant-arknights), edit the script according to the post-install instruction.
- Nixpkgs: [maa-assistant-arknights](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-assistant-arknights/package.nix)
2. Navigate to `./MAA-v{version}-linux-{architecture}/Python/` and open the `sample.py` file
2. Open `sample.py` in `./MAA-v{VERSION}-linux-{ARCH}/Python/`
::: tip
The precompiled version includes dynamic libraries compiled on relatively new Linux distributions (Ubuntu 22.04). If your system has an older libstdc++ version, you might encounter ABI incompatibility issues.
You can refer to the [Linux Compilation Tutorial](../../develop/linux-tutorial.md) to recompile or use a container solution.
:::
> **Note**
> The precompiled version is built in a relatively new distro (Ubuntu 22.04), you may run into binary compatability problem, if libstdc++ in your environment is too old.
> Where you should reference to [Linux tutorial](../../develop/linux-tutorial.md), or run inside a container instead.
#### 2. ADB Configuration
#### 2. `adb` Settings
1. Find the line [`if asst.connect('adb.exe', '127.0.0.1:5554'):`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/b4fc3528decd6777441a8aca684c22d35d2b2574/src/Python/sample.py#L62)
1. Target to [`if asst.connect('adb.exe', '127.0.0.1:5554'):`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/722f0ddd4765715199a5dc90ea1bec2940322344/src/Python/sample.py#L48)
2. ADB Tool Configuration
2. `adb` Tools Settings
- If using `Android Studio`'s `AVD` emulator, it comes with ADB. You can directly specify the ADB path to replace `adb.exe`, typically found in `$HOME/Android/Sdk/platform-tools/`, for example:
- If you use `avd` in `Android Studio` as your emulator, it contains `adb` that you can use it directly. Just fill in your `adb` path in `adb.exe`, you can usually find it in `$HOME/Android/Sdk/platform-tools/` , eg.:
```python
if asst.connect("/home/foo/Android/Sdk/platform-tools/adb", "emulator's ADB address"):
```
```python
if asst.connect("/home/foo/Android/Sdk/platform-tools/adb", "avd_ID"):
```
- For other emulators, first install ADB: `$ sudo apt install adb`, then either specify the path or simply use `adb` if it's in your `PATH` environment variable.
- If you use other emulators, you have to install `adb` first: `$ sudo apt install adb` and then fill in the path of adb or just fill in `adb` if you had put it into the `PATH` environment variable.
3. Getting the Emulator's ADB Address
3. Emulator `adb` ID Settings
- Use the ADB tool directly: `$ adb_path devices`, for example:
- You can use the adb tool directly: `$ ${adb_path} devices` , eg.:
```shell
$ /home/foo/Android/Sdk/platform-tools/adb devices
List of devices attached
emulator-5554 device
```
```shell
$ /home/foo/Android/Sdk/platform-tools/adb devices
List of devices attached
emulator-5554 device
```
- The returned `emulator-5554` is the emulator's ADB address. Replace `127.0.0.1:5555` with it, for example:
- `emulator-5554` that the terminal returns is the ID of emulator adb, replacing `127.0.0.1:5555` with it, eg.
```python
if asst.connect("/home/foo/Android/Sdk/platform-tools/adb", "emulator-5554"):
```
```python
if asst.connect("/home/foo/Android/Sdk/platform-tools/adb", "emulator-5554"):
```
4. Now you can test with `$ python3 sample.py`. If it returns "Connection successful," you're ready to proceed.
4. Now you can test: `$ python3 sample.py` , if return `连接成功` , you almost finish setting.
#### 3. Task Configuration
#### 3. Tasks Settings
Custom tasks: Refer to the [Integration Documentation](../../protocol/integration.md) and modify the [`# Task parameters can be found in docs/integration.md`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/722f0ddd4765715199a5dc90ea1bec2940322344/src/Python/sample.py#L54) section in `sample.py`
Customizing tasks: Reference to [AsstAppendTask](../../protocol/integration.md#asstappendtask) and modify [`# 任务及参数请参考 docs/集成文档.md`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/722f0ddd4765715199a5dc90ea1bec2940322344/src/Python/sample.py#L54) section in `sample.py`.
## Emulator Support
## Emulator Supports
### ✅ [AVD](https://developer.android.com/studio/run/managing-avds)
Requirements: 16:9 screen resolution larger than 720p
Requests: Resolution should be 16:9 and above 720p
Recommended configuration: x86_64 architecture (R - 30 - x86_64 - Android 11.0) with MAA's Linux x64 dynamic library
Note: Starting from Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode. Please switch to other touch modes, or **temporarily** switch SELinux to `Permissive` mode.
Recommendation: x86\_64 architecture (R - 30 - x86\_64 - Android 11.0) with `Linux x64 动态库` in MAA
### ⚠️ [Genymotion](https://www.genymotion.com/)
High Android versions include x86_64 framework. Lightweight but tends to crash when running Arknights.
Native x86\_64 architecture in high version of Android, light weight but easy to crash when running Arknights.
Not thoroughly tested yet, but ADB functionality and path retrieval work without issues.
We have not testing strictly, but adb functions and path have no error.
## Containerized Android Support
## Containerized Android
::: tip
The following solutions typically require specific kernel modules. Please install the appropriate modules according to your distribution and the particular solution.
:::
> **Note**
> The following solutions are likely to depend on special kernel modules, make sure to have them installed accordingly.
### ✅ [Waydroid](https://waydro.id/)
After installation, you need to reset the resolution (to 16:9 ratio and greater than 720p, then restart):
Need to reset the resolution to 16:9 (You can set it above 720P):
```shell
waydroid prop set persist.waydroid.width 1280
waydroid prop set persist.waydroid.height 720
```
To set up ADB IP address: Go to `Settings` - `About` - `IP address`, note the first `IP`, and use `${recorded IP}:5555` in `sample.py` for the ADB IP.
After restarting, record `IP address` in `Setting` - `About phone` , fill `${IP address}:5555` to the adb IP address in `sample.py` .
If using amdgpu, the `screencap` command might output messages to stderr, causing image decoding failures.
You can run `adb exec-out screencap | xxd | head` and check if there's text like `/vendor/etc/hwdata/amdgpu.ids: No such file...` in the output.
If present, try changing the screenshot command in `resource/config.json` from `adb exec-out screencap` to `adb exec-out 'screencap 2>/dev/null'`.
If you are using amdgpu, `screencap` command may write messages to stderr, causing image decoding error.
Run `adb exec-out screencap | xxd | head` to check if there is something like `/vendor/etc/hwdata/amdgpu.ids: No such file...` in the output.
Modify screencap commands in `resource/config.json` from `adb exec-out screencap` to `adb exec-out 'screencap 2>/dev/null'` as a workaround.
### ✅ [redroid](https://github.com/remote-android/redroid-doc)
Android 11 version images can run the game normally. Make sure to expose port 5555 for ADB.
Arknights runs properly in Android 11 image. Do remember to expose port 5555 for adb.

View File

@@ -3,62 +3,62 @@ order: 2
icon: basil:apple-solid
---
# macOS Emulators
# Mac Emulator
## Apple Silicon Chips
### ✅ [PlayCover](https://playcover.io) (Runs most fluently as it's native 🚀)
### ✅ [PlayCover](https://playcover.io) (The software runs most fluently for its nativity 🚀)
Experimental support. Please submit issues if you encounter problems, and include `MacOS` in the title.
Compatible in beta, plz submit issue marked with `MacOS` when encounter errors.
Note: Due to macOS system limitations, screenshot issues may occur when minimizing the game window, switching to other windows while in Stage Manager, or moving the window to other desktops/screens. Related issue: [#4371](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/4371#issuecomment-1527977512)
P.S.: For the reason of `MacOS` mechanism itself, errors might occur when `PlayCover` is minimized and you switch to others windows. The errors of screenshot might crash `MAA`. Reference 👉🏻️[issue](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/4371#issuecomment-1527977512)
0. Requirements: MAA version v4.13.0-rc.1 or newer
1. Requests: MAA version above v4.13.0-rc.1
1. Download and install the [forked version of PlayCover](https://github.com/hguandl/PlayCover/releases).
2. Download and install [fork version of PlayCover](https://github.com/hguandl/PlayCover/releases)
2. Download the [decrypted Arknights client package](https://decrypt.day/app/id1454663939) and install it in PlayCover.
3. Download [decrypted version of Arknights](https://decrypt.day/app/id1454663939), and then install in PlayCover.
3. Right-click on Arknights in PlayCover, select `Settings` - `Bypasses`, check `Enable PlayChain`, `Enable Jailbreak Detection Bypass`, `Insert Introspection Libraries`, `MaaTools`, then click `OK`.
4. Right-click Arknights in PlayCover, choose `Setting` - `Jailbreak Bypass`, enable `Enable PlayChain`, `Enable Jailbreak Bypass (Alpha)`, `Insert Introspection Library`, `MaaTools`, then click `OK`.
4. Now launch Arknights, which should run normally. The title bar will end with `[localhost:port]`, indicating successful activation.
5. Relaunch Arknights, `[localhost:${port number}]` will appear above, meaning launching is successful.
5. In MAA, go to `Settings` - `Connection Settings`, set `Touch Mode` to `MacPlayTools`. For `Connection Address`, enter the content inside the `[]` from the title bar.
6. In MAA, click `Settings` - `Connection Settings`, `Minitouch` choose `MacPlayTools`. `Connection Address` filling the content in `[]` .
6. Setup complete! MAA should now connect successfully. If you encounter image recognition errors, try setting the resolution to 1080P in PlayCover.
7. Finish, MAA is able to build connection. If errors occur in image recognition, you could try to set resolution to 1080P in PlayCover.
7. Steps 3-5 only need to be done once. After that, just launch Arknights. After each Arknights client update, you'll need to repeat step 2.
### ✅ [MuMu Emulator Pro](https://mumu.163.com/mac/)
Supported, but less thoroughly tested. Requires using a touch mode other than `MacPlayTools`. Related issue: [#8098](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/8098)
8. 3-5 do not need to be repeated, you could just launch Arknights after that. While you have to repeat step 2 if Arknights is updated.
### ✅ [AVD](https://developer.android.com/studio/run/managing-avds)
Supported, but starting from Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode. Please switch to other touch modes, or **temporarily** switch SELinux to `Permissive` mode.
Compatible
### ✅ [BlueStacks Air](https://www.bluestacks.com/mac) (Free, optimized for Apple M-series chips)
Supported and tested. Can be connected using MaaTouch via `127.0.0.1:5555`.
Supported, tested, and can be connected via maatouch at `127.0.0.1:5555`.
You need to enable `Android Debugging (ADB)` in the emulator's `Settings` - `Advanced` section.
You need to enable **"Android Debugging (ADB)"** in the emulator's **`Settings`** - **`Advanced`** section.
## Intel Chips
::: tip
Due to limited development resources for the Mac version, updates are relatively slower. We recommend using Boot Camp to install Windows and using the Windows version of MAA instead.
Due to a lack of manpower for Mac version development, updates are relatively slower. It is recommended to use Mac's built-in multi-system feature to install Windows and use the Windows version of MAA.
:::
### ✅ [BlueStacks](https://www.bluestacks.com/)
### ✅ [Bluestacks-CN 5](https://www.bluestacks.cn/)
Fully compatible. You need to enable `Android Debug Bridge` in the emulator's `Settings` - `Advanced`.
Fully compatible. Need to turn on `Settings` - `Engine Settings` - `Allow ADB connection`.
### ✅ [Nox Player](https://www.bignox.com/)
### ✅ [Bluestacks 5](https://www.bluestacks.com/tw/index.html)
Fully compatible. Need to turn on `Settings` - `Advanced` - `Android Debug Bridge`.
### ✅ [Nox](https://www.yeshen.com/)
Fully compatible.
Note: On macOS, the Nox ADB binary is located at `/Applications/NoxAppPlayer.app/Contents/MacOS/adb`. In the `MacOS` parent directory, you can use the `adb devices` command to check the ADB port.
P.S.: Nox adb bin file path in Mac is `/Applications/NoxAppPlayer.app/Contents/MacOS/adb` , in parent path `MacOS` you are able to use `adb devices` command to get adb path.
### ✅ [AVD](https://developer.android.com/studio/run/managing-avds)
Supported, but starting from Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode. Please switch to other touch modes, or **temporarily** switch SELinux to `Permissive` mode.
Compatible.

View File

@@ -3,9 +3,13 @@ order: 1
icon: ri:windows-fill
---
# Windows Emulators
# Windows Emulator
The following emulators are displayed in random order with no particular ranking.
:::warning
TODO: replace these Chinese emulators links with English ones
:::
The following emulators are displayed randomly in no particular order.
<script setup>
import MarkdownIt from 'markdown-it'
@@ -21,29 +25,29 @@ const shuffleArray = (array) => {
const fullySupport = shuffleArray([
{
name: 'BlueStacks 5',
name: 'Bluestacks 5',
link: 'https://www.bluestacks.com/',
note: 'Fully compatible. Need to turn on ADB Connectivity in the emulator `Settings` → `Advanced` → `Android Debug Bridge` → `Enable`. Known to be compatible with Hyper-V.\n\n- Recommended to download [Offline Installer](https://support.bluestacks.com/hc/en-us/articles/4402611273485-BlueStacks-5-offline-installer) to avoid slow and bundled installation; recommend installing [Android 11](https://support.bluestacks.com/hc/en-us/articles/4402611273485-BlueStacks-5-offline-installer#:~:text=To%20install%20BlueStacks%205%20Android%2011) version; to uninstall it, please use the official [Uninstall Tool](https://support.bluestacks.com/hc/en-us/articles/360057724751-How-to-uninstall-BlueStacks-5-BlueStacks-X-and-BlueStacks-Services-completely-from-your-PC) to get rid of residues.\n- If the ADB port number keeps changing irregularly and is different every time you start it, it may be because your computer has [Hyper-V](https://support.bluestacks.com/hc/en-us/articles/4415238471053-System-requirements-for-BlueStacks-5-on-Hyper-V-enabled-Windows-10-and-11) enabled. MAA will now try to automatically read the port number from the BlueStacks emulator configuration file. If this doesn\'t work, or you need to use multiple instances, or have installed multiple emulator cores, please refer to [Connection Settings](../connection.html#bluestacks-emulator-hyper-v-port-number-changes-every-startup) to make adjustments. Since Hyper-V runs as administrator, operations that don\'t involve ADB such as automatic emulator shutdown or connection detection also need MAA to run as administrator.',
note: 'Fully compatible. Need to turn on ADB Connectivity in the emulator `Settings` → `Advanced` → `Android Debug Bridge` → `Enable`. Known to be compatible with Hyper-V.\n\n- Recommended to download [Offline Installer](https://support.bluestacks.com/hc/en-us/articles/4402611273485-BlueStacks-5-offline-installer) to avoid slow and bundled installation; recommend installing [Android 11](https://support.bluestacks.com/hc/en-us/articles/4402611273485-BlueStacks-5-offline-installer#:~:text=To%20install%20BlueStacks%205%20Android%2011) version; to uninstall it, please use the official [Uninstall Tool](https://support.bluestacks.com/hc/en-us/articles/360057724751-How-to-uninstall-BlueStacks-5-BlueStacks-X-and-BlueStacks-Services-completely-from-your-PC) to get rid of the residue.\n- If the adb port number keeps changing irregularly and is different every time you start it, it may be because your computer has [Hyper-V](https://support.bluestacks.com/hc/en-us/articles/4415238471053-System-requirements-for-BlueStacks-5-on-Hyper-V-enabled-Windows-10-and-11) enabled. MAA will now try to automatically read the port number within the Blue Stacker emulator configuration file, if this does not work/you have a need to multi-open/have more than one emulator kernel installed, please refer to the [Connection (TODO)](../connection.html#the-port-number-of-bluestack-emulator-hyper-v-is-different-every-time-it-is-started) to make changes. Since Hyper-V runs as administrator, operations that don\'t involve adb such as auto-shutdown of the emulator, auto-detect connection, etc. also need to run MAA as administrator.',
},
{
name: 'MuMu Emulator',
link: 'https://www.mumuglobal.com/',
note: 'Fully compatible, with additional support for [Screenshot Enhanced Mode](../connection.html#mumu-screenshot-enhanced-mode). Known to be compatible with Hyper-V.\n\n- The "Exit emulator when done" function may occasionally have issues. If you encounter problems, please report them to MuMu\'s official support.\n- When running multiple instances, you need to check the port information of each instance through the ADB button in MuMu Multi-Instance Manager, then change the port number in MAA `Settings` - `Connection Settings` to match the corresponding port.',
name: 'MuMu Emulator 12',
link: 'https://mumu.163.com/',
note: 'Fully compatible, with additional support for the [Screenshot Enhanced Mode](../connection.html#mumu-screenshot-enhanced-mode). Known to be compatible with Hyper-V.\n\n- The "Exit emulator when done" function may occasionally be abnormal, if you encounter it, please contact MuMu official for feedback.\n- You need to check the port information of the corresponding instance through the ADB button of MuMu 12 Multiple Opener when you open more than one instance, and change the port number of the connection address in MAA `Settings` - `Connection Settings` to the corresponding port.',
},
{
name: 'LDPlayer',
link: 'https://www.ldplayer.net/',
note: 'Fully compatible, with additional support for [Screenshot Enhanced Mode](../connection.html#ld-screenshot-enhanced-mode). Known to be compatible with Hyper-V.\n\n- LDPlayer 9 installer will automatically and silently disable Hyper-V during the installation process. Please be aware of this if you need Hyper-V for other purposes.',
link: 'https://www.ldmnq.com/',
note: 'Fully compatible, with additional support for the [Screenshot Enhanced Mode](../connection.html#ld-screenshot-enhanced-mode). Need to turn on ADB Connectivity in the emulator : `Settings``Others``ADB debugging``Enable local connection`. Known to be compatible with Hyper-V.\n\n- LDPlayer 9 installer will automatically and silently disable Hyper-V during the installation process. Please pay attention if you have related needs.',
},
{
name: 'Nox Player',
link: 'https://www.bignox.com/',
note: 'Fully compatible, but less thoroughly tested. Known to be compatible with Hyper-V.',
name: 'Nox',
link: 'https://www.yeshen.com/',
note: 'Fully compatible, but less tested. Known to be compatible with Hyper-V.',
},
{
name: 'MEmu Play',
link: 'https://www.memuplay.com/',
note: 'Fully compatible, but less thoroughly tested.',
name: 'Memu',
link: 'https://www.xyaz.cn/',
note: 'Fully compatible, but less tested.',
},
]);
@@ -51,22 +55,22 @@ const partiallySupport = shuffleArray([
{
name: 'MuMu Emulator 6',
link: 'https://mumu.163.com/update/win/',
note: 'Support has been dropped since MAA v5.1.0, and NetEase stopped maintaining it on August 15, 2023.\n\n- No longer supports automatic connection detection. You need to use general connection configuration and manually configure ADB path and connection address.\n- You need to run `Force Replace ADB` in `Settings` - `Connection Settings` to use efficient touch modes like Minitouch and MaaTouch.\n- You need to run MAA with administrator privileges to use the "Exit Emulator When Done" function.\n- MuMu 6\'s unusual default resolutions are not supported. You need to change it to standard 16:9 ratios like `1280x720` or `1920x1080`.\n- MuMu 6 multi-instance uses the same ADB port for all instances, so MAA cannot support multiple MuMu 6 instances.',
note: 'Support has been dropped since MAA v5.1.0 and NetEase has stopped maintaining it on 15-08-2023.\n\n- No longer support auto-detect connection, need to use generic connection configuration and manually configure adb path and connection address.\n- Need to run `Forced Replacement of ADB` in `Settings` - `Connection` to use efficient touch modes such as Minitouch, MaaTouch.\n- You need to run MAA with administrator privileges to use the "Exit Emulator When Done" function.\n- MuMu 6 default resolution is not supported, you need to change it to `1280x720`, `1920x1080` and other 16:9 ratio.\n- MuMu 6 multi-open uses the same adb port, so it can\'t support multi-open MuMu 6.',
},
{
name: 'Windows Subsystem for Android™ (WSA)',
name: 'Windows Subsystem for Android™',
link: 'https://learn.microsoft.com/en-us/windows/android/wsa/',
note: 'Support has been dropped since MAA v5.2.0, and Microsoft stopped maintaining it on March 5, 2025.\n\n- Requires using [custom connection](../connection.html) method.\n- For WSA 2204 or later versions (version number can be found in subsystem settings under `About`), select `General Configuration` for connection configuration.\n- For WSA 2203 or older versions (version number appears at the top of subsystem settings page), select `WSA Older Versions` for connection configuration.\n- Since MAA only properly supports `16:9` resolutions of 720p or higher, please manually adjust the window size to be as close to 16:9 ratio as possible. (If your monitor is 16:9, you can press `F11` for fullscreen).\n- During task execution, try to ensure Arknights remains in the foreground with no other Android apps running simultaneously, otherwise the game may pause or task recognition may fail.\n- WSA sometimes inexplicably captures white screens during screenshots, causing recognition issues. Not recommended for use.',
note: 'Support has been dropped since MAA v5.2.0 and will be discontinued by Microsoft on 05-03-2025.\n\n- Requires the use of [custom connection](../details.html#Custom connection) is required.\n- WSA 2204 or later (the version number is in the `About` page of the subsystem settings), select `Common Configuration` for the connection configuration.\n- WSA 2203 or older (the version number is at the top of the subsystem setup page), for the connection configuration select `WSA Older Versions`.\n- Since this software only supports 720p or higher `16:9` resolution better, please manually drag the window size as close to the 16:9 ratio as possible. (If your monitor is 16:9, you can press `F11` to go full screen).\n- Please try to make sure that Arknights is in the foreground and no other Android apps are running in the foreground at the same time, otherwise it may cause the game to pause or the task recognition error.\n- WSA\'s screenshots often somehow capture a white screen, resulting in recognition of abnormalities, or not recommended to use.',
},
{
name: 'AVD',
link: 'https://developer.android.com/studio/run/managing-avds',
note: 'Theoretically supported.\n\n- Starting from Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode. Please switch to other touch modes, or **temporarily** switch SELinux to `Permissive` mode.\n- AVD is designed for development debugging, not gaming. Other emulators specifically designed for gaming are recommended instead.',
note: 'Theoretical support.\n\n- Starting from Android 10, Minitouch is no longer available when SELinux is in `Enforcing` mode, please switch to other touch modes, or switch SELinux **temporary** to `Permissive` mode.\n- AVD is made for debugging, it is more recommended to use other emulators designed for gaming.',
},
{
name: 'Google Play Games (Developer)',
link: 'https://developer.android.com/games/playgames/emulator',
note: 'Theoretically supported. Requires Hyper-V to be enabled and a Google account to be logged in.\n\n- You need to use [custom connection](../connection.html) to connect, with ADB port `6520`.\n- Due to SELinux policies in Android 10 and later, Minitouch cannot work properly. Please switch to other touch modes.\n- The first connection attempt after each emulator startup will fail. Enable `Attempt to kill and restart ADB process after connection failure`.',
link: 'https://developer.android.com/games/playgames/emulator?hl=zh-cn',
note: 'Theoretical support. Hyper-V must be enabled, and a Google account must be logged in.\n\n- You need to use [custom connection](../connection.html) to connect, the ADB port is `6520`.\n- Due to the SELinux policy of Android 10 and later versions, Minitouch cannot work properly, please switch to other touch modes.\n- The first connection after each emulator startup will fail, you need to check `Attempt to kill and restart ADB process after connection failure`.',
},
]);
@@ -74,7 +78,7 @@ const notSupport = shuffleArray([
{
name: 'Google Play Games',
link: 'https://play.google.com/googleplaygames',
note: 'Not supported. The [Consumer Client](https://developer.android.com/games/playgames/emulator#installing-game-consumer) cannot connect via ADB.',
note: 'Not supported, [Consumer Client](https://developer.android.com/games/playgames/pg-emulator#installing-game-consumer) cannot use ADB.',
},
]);

View File

@@ -9,128 +9,134 @@ If this is your first time using MAA, please read [Getting Started](./newbie.md)
::: warning
If MAA fails to run after an update, or if you've arrived here from MAA's error window, it's most likely due to outdated runtime libraries.
The most common issue is related to runtime libraries, and many people keep asking about it without reading the documentation, so we changed the pinned message to this. It's frustrating.
If MAA fails to run after an update, or if you've reached this page via an error window in MAA, it's highly likely due to outdated runtime libraries.
The most frequent issue is runtime-related, yet many users ignore the documentation and ask around, so we replaced the pinned message with this. It's frustrating.
Please run `DependencySetup_依赖库安装.bat` in the MAA directory, or execute the following command in terminal:
Please run `DependencySetup_依赖库安装.bat` in the MAA directory, or execute the commands below in a terminal,
```sh
winget install "Microsoft.VCRedist.2015+.x64" --override "/repair /passive /norestart" --force --uninstall-previous --accept-package-agreements && winget install "Microsoft.DotNet.DesktopRuntime.8" --override "/repair /passive /norestart" --force --uninstall-previous --accept-package-agreements
```
Or manually download and install these <u>**two**</u> runtime libraries to solve the problem:
or manually download and install the following <u>**two**</u> runtime libraries to resolve the issue.
- [Visual C++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe)
- [Visual C++ Redistributable x64](https://aka.ms/vs/17/release/vc_redist.x64.exe)
- [.NET Desktop Runtime 8](https://aka.ms/dotnet/8.0/windowsdesktop-runtime-win-x64.exe)
:::
## Software won't run/crashes/shows errors
## The program crashes immediately when I try to run it
### Download/Installation issues
### Incomplete file downloaded
- A complete MAA software package is named "MAA-`version`-`platform`-`architecture`.zip"; others are "components" that cannot be used independently. Please read carefully.
In most cases, you need the x64 architecture of MAA, meaning you should download `MAA-*-win-x64.zip`, not `MAA-*-win-arm64.zip`.
- If you find missing or non-working features after an automatic update, the update process may have had issues. Please download and extract the complete installation package again. After extraction, drag the `config` folder from your old `MAA` folder into the newly extracted `MAA` folder.
- If you don't have a complete package of this software already, please DO NOT download the zip files marked with `OTA` in the file name, which are for incremental updates and shall not be used alone. In most cases, Windows users should download `MAA-vX.X.X-win-x64.zip`.
In most cases, you need x64 operating system and x64 variant of MAA, i.e. `MAA-*-win-x64.zip`. There is no support for 32-bit (x86) operating systems.
- If you find that certain features are missing or not working after an automatic update, it may be due to an issue during the update process. Please re-download and extract the full installation package. After extraction, drag the `config` folder from the old `MAA` folder into the newly extracted `MAA` folder.
### Runtime library issues
### Missing runtime libraries
Find the up arrow at the bottom right of the webpage and click it.
Find the upward ↑ arrow at the bottom right corner of the webpage and click it.
### System issues
### System Issues
- MAA doesn't support 32-bit operating systems or Windows 7/8/8.1.
- The runtime installations above require Component Store Service (CBS, TrustedInstaller/TiWorker, WinSxS).
If these services are damaged, installation will fail.
- MAA does not support 32-bit operating systems and does not support Windows 7 / 8 / 8.1.
- The above runtime installations all require the Component Store Service (CBS, TrustedInstaller/TiWorker, WinSxS).
If the Component Store Service is damaged, it cannot be installed properly.
We cannot provide repair solutions other than reinstalling your system. Please avoid using "slimmed" system versions without clear documentation of what was removed, or extremely outdated systems.
We cannot provide repair suggestions other than reinstalling the system, so please avoid using "slimmed-down" systems that do not specify slimming items and slimming risks, or very old versions of systems.
#### Windows N/KN
For Windows N/KN (European/Korean versions), you also need to install the [Media Feature Pack](https://support.microsoft.com/zh-cn/topic/c1c6fffa-d052-8338-7a79-a4bb980a700a).
For Windows N/KN (Europe/Korea), you also need to install the [Media Feature Pack](https://support.microsoft.com/en-us/topic/c1c6fffa-d052-8338-7a79-a4bb980a700a).
#### Windows 7
#### Notes on Windows 7
.NET 8 doesn't support Windows 7/8/8.1 systems<sup>[source](https://github.com/dotnet/core/issues/7556)</sup>, so MAA no longer supports them either. The last usable .NET 8 version is [`v5.4.0-beta.1.d035.gd2e5001e7`](https://github.com/MaaAssistantArknights/MaaRelease/releases/tag/v5.4.0-beta.1.d035.gd2e5001e7); the last usable .NET 4.8 version is [`v4.28.8`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/releases/tag/v4.28.8). Self-compilation feasibility remains undetermined.
.NET 8 does not support Windows 7 / 8 / 8.1 systems<sup>[source](https://github.com/dotnet/core/issues/7556)</sup>, so MAA also no longer supports them. The last available .NET 8 version is [`v5.4.0-beta.1.d035.gd2e5001e7`](https://github.com/MaaAssistantArknights/MaaRelease/releases/tag/v5.4.0-beta.1.d035.gd2e5001e7); the last available .NET 4.8 version is [`v4.28.8`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/releases/tag/v4.28.8). The feasibility of self-compilation has not yet been determined.
For Windows 7, before installing the two runtime libraries mentioned above, check if these patches are installed:
For Windows 7, before installing the two runtime libraries mentioned above, you also need to check if the following patches are installed:
1. [Windows 7 Service Pack 1](https://support.microsoft.com/zh-cn/windows/b3da2c0f-cdb6-0572-8596-bab972897f61)
2. SHA-2 code signing patches:
- KB4474419: [Download link 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu), [Download link 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)
- KB4490628: [Download link 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu), [Download link 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)
3. Platform Update for Windows 7 (DXGI 1.2, Direct3D 11.1, KB2670838): [Download link 1](https://catalog.s.download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu), [Download link 2](http://download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu)
1. [Windows 7 Service Pack 1](https://support.microsoft.com/en-us/windows/b3da2c0f-cdb6-0572-8596-bab972897f61)
2. SHA-2 code-signing update
- KB4474419[link 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu), [link 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)
- KB4490628[link 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu), [link 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)
3. Platform Update for Windows 7 (DXGI 1.2 & Direct3D 11.1, KB2670838)[link 1](https://catalog.s.download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu), [link 2](http://download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu)
##### Workaround for .NET 8 applications running abnormally on Windows 7 [#8238](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/8238)
##### .NET 8 applications running on Windows 7 mitigation measures [#8238](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/8238)
When running .NET 8 applications on Windows 7, abnormal memory usage can occur. Follow these steps to mitigate it. Windows 8/8.1 hasn't been tested; if similar issues occur, please open an Issue to remind us to update the documentation.
When running .NET 8 applications on Windows 7, there is an issue with abnormal memory usage. Please refer to the following mitigation measures. Windows 8/8.1 has not been tested. If the same issue exists, please kindly submit an issue to remind us to update the documentation.
1. Open `Computer`, right-click in empty space, click Properties, click `Advanced system settings` on the left, and click `Environment Variables`.
2. Create a new system variable with name `DOTNET_EnableWriteXorExecute` and value `0`.
3. Restart your computer.
1. Open `Computer`, right-click on the blank space, click Properties, click `Advanced system settings` on the left, and click `Environment Variables`.
2. Create a new system variable, variable name `DOTNET_EnableWriteXorExecute`, variable value `0`.
3. Restart the computer.
## Connection errors
## Connection Error
### Verify ADB and connection address are correct
- Tips: please refer to the [List of the Supported Emulators](./device/) section to ensure that the emulator you are using is officially supported and that your configuration is correct.
- If you are using software such as a game accelerator, please close the software, RESTART your computer and try again.
- Please check your decompression software - in some cases, using uncommon software such as `7z` or _other niche decompression software_ may cause errors in Minitouch-related files.
See [Connection Settings](./connection.md).
### Make sure ADB and address are correct
### Close existing ADB processes
Check [Connection](./connection.md)
After closing MAA, check `Task Manager` - `Details` for processes containing `adb`. If found, end them and retry connecting.
### Change emulator
### Properly use multiple ADB instances
Change to another emulator, such as [Bluestacks international version](https://www.bluestacks.com/download.html) Nougat 64 bit.
When ADB versions differ, newly started processes will close older ones. If you need to run multiple ADB instances simultaneously (e.g., Android Studio, Alas, phone managers), ensure they use the same version.
_After installation of Bluestack, you need to enable `Android Debug Bridge` in the settings._
### Avoid game accelerators
### Close extra adb processes
Some accelerators require restarting MAA, ADB, and the emulator after enabling or disabling acceleration.
- Close MAA and check for any adb processes in the task manager. If there are any, please close them and retry.
For using UU Accelerator with MuMu, refer to the [official documentation](https://mumu.163.com/help/20240321/35047_1144608.html).
### Restart computer
### Restart your computer
Try restarting your computer.
Restarting solves 97% of problems. (Trust me)
## Connected successfully, then stuck, not operating at all
### Try a different emulator
The adb version packaged with some emulators is too old and does not support minitouch. Please open MAA with administrator privileges and navigate to `Settings` - `Connection Settings` - `Forced Replace ADB`. (It is recommended to close the emulator and restart MAA before proceeding, otherwise, the replacement may not be successful.)
Please refer to [Emulator and Device Support](./device/).
The emulator will reset the ADB version after updating. If the problems occur again, please repeat the above steps. Or you can try to use the [custom connection](./connection.md) method to solve it once and for all.
## Connected but no operation
If it still doesn't work, please retry after switching to `MaaTouch` from `Minitouch` in `Settings` - `Connection Settings`.
Some emulators come with outdated ADB versions that don't support `Minitouch` or `MaaTouch`.
## Connected successfully, but actions are slow or errors are frequent
Run MAA as administrator, close the emulator, restart MAA, and click `MAA Settings` - `Connection Settings` - `Force Replace ADB`.
- The Copilot requires you to go to the screen with the `Start` button. Please confirm they are not related.
- If you are using a non-CN client, please go to MAA Settings - Start-Up Settings - Select your client version. Not all features are currently supported for non-CN clients, please refer to docs.
- If you are running the Auto-I.S. function, please PIN UP the I.S. theme you want in the game, and select I.S. theme in MAA `Task Settings` - `Auto I.S.`.
- If Copilot frequently pauses without deploying operators, please disable `Pause Deployment` in `Settings` - `Game Settings`.
- If Auto Squad fails to recognize operators properly, please cancel the special focus on the corresponding operators.
- The input method `Adb Input` is naturally slow. It is recommended to use `MaaTouch` or `Minitouch` instead.
Emulator updates may overwrite the ADB file. If the issue returns after an update, try replacing again or use [alternative ADB](./connection.md#use-adb-provided-by-google).
### Prompt that the screenshot takes a long time / is too long
## Connected but operations are laggy, abnormal, or error-prone
- MAA currently supports 3 screenshot methods: `RawByNc`, `RawWithGzip`, and `Encode`. When the average screenshot time of executing a task is >400 / >800, a prompt message will be output (a single task will only be output once).
- `Settings - Connection Settings` will display the minimum/average/maximum time taken for the last 30 screenshots, refreshed every 10 screenshots.
- Automatic combat functions (such as I.S.) are greatly affected by the time taken to take screenshots.
- This time consumption is unrelated to MAA, but related to computer performance, current usage, or emulator. You can try cleaning up background processes, changing emulators, or upgrading computer configurations.
- If you've enabled `Notched Screen UI Adaptation`, set it to 0.
- If using a non-CN client, first select your client version in `Settings` - `Game Settings` - `Client Type`. Some features may not be fully adapted for non-CN clients; refer to the corresponding documentation.
- For Integrated Strategy automation, check the [Auto Integrated Strategy documentation](./introduction/integrated-strategy.md) and correctly select the theme in `Auto Integrated Strategy` - `Integrated Strategy Theme`.
- If auto-combat frequently pauses without deploying operators, disable `Matchstick Mode` in `Settings` - `Operation Settings`.
- If auto-squad formation can't recognize operators correctly, remove special focus from those operators.
- `Adb Input` touch mode is naturally slow; try switching to other modes for functions like auto-combat.
## About Windows UAC
### "Screenshot takes too long" message
MAA should not require Windows UAC administrator privileges to run all functions. The functionalities related to administrator privileges are as follows:
- MAA currently supports three ADB-based screenshot methods: `RawByNc`, `RawWithGzip`, and `Encode`. When average screenshot time exceeds 400/800ms, a notification appears once per task.
- `Settings - Connection Settings` displays min/avg/max times for the last 30 screenshots, refreshed every 10 screenshots.
- Auto-combat features (like Integrated Strategy) are heavily affected by screenshot times.
- Screenshot performance is unrelated to MAA but depends on computer performance, background processes, or emulator. Try clearing background tasks, changing emulators, or upgrading your computer.
1. `Auto Detect Connection`: Administrator privileges are required when the target emulator is running with administrator rights.
2. `Close Emulator After Completion`: Administrator privileges are required when the target emulator is running with administrator rights.
3. `Start MAA Automatically on Boot`: It is not possible to set automatic startup with administrator privileges.
4. When MAA is incorrectly extracted to a path that requires administrator privileges for writing, such as `C:\` or `C:\Program Files\`.
## Administrator permissions issues
There have been reports that systems with UAC disabled may have the issue where "even without selecting 'Run as Administrator' by right-clicking, it will still run with administrator privileges." It is recommended to enable UAC to avoid unintended privilege escalation.
MAA shouldn't need Windows UAC administrator privileges for any functionality. Current admin-related functions include:
## The download speed is slow and the mirror site is not accessible
1. `Auto-detect connection`: Administrator rights needed when the target emulator runs as administrator.
2. `Close emulator when done`: Administrator rights needed when the target emulator runs as administrator.
3. `Auto-start MAA at boot`: Cannot be set when running as administrator.
4. When MAA is incorrectly extracted to paths requiring admin rights for writing, like `C:\` or `C:\Program Files\`.
1. Go to [Download](../readme.md) to get the link (non-mirror) you want to download.
2. Find the link to the file you need to download.
3. Right-click it and select `Copy link address`.
4. Paste the link into your browser.
5. Replace the `github.com` in the link with `download.fastgit.org`.
6. Press `Enter` to download.
Reports indicate that systems with disabled UAC may run applications as administrator even without explicitly selecting "Run as administrator." We recommend enabling UAC to prevent unexpected privilege escalation.
## Download halfway and prompt "login"/"authentication"
## Download stops midway with "login"/"authentication" prompt
Please use a browser / IDM / FDM or other downloaders to download files, **DO NOT use Thunder!**
Please use a browser / IDM / FDM and other regular downloaders to download files, **Do NOT fucking use Thunder!**

View File

@@ -3,125 +3,113 @@ order: 3
icon: hugeicons:brain-02
---
# Sanity Farming
# Combat
::: important This page may be outdated.
:::
## General Settings
- The `Use Sanity Potion` + `Use Originium` and `Perform Battles`+ `Material` options work as OR conditions - the task will stop when any of these conditions is met.
- Combat options include `Use Sanity Potion + Use Originium`, `Perform Battles` and `Material`, you can specify any of them. The combat task stops once one of the specifications is met.
- `Use Sanity Potion` specifies how many times to replenish sanity (may use multiple potions at once).
- `Use Originium` specifies how many Originium to use (one at a time). Originium won't be used if sanity potions are available.
- `Perform Battles` specifies the number of battles to complete (e.g., "stop after 15 runs").
- `Material` specifies how many of a specific material to obtain (e.g., "stop after getting 5 Orirock").
- `Use Sanity Potion` specifies the maximum used amount of sanity potions. Multiple potions may be used at a time.
- `Use Originium` specifies the maximum used amount of Originium. It is used one at a time. The Originium will not be used when there are Sanity Potions in the depot.
- `Perform Battles` specifies the number of battles to perform at most.
- `Material` specifies the number of materials to collect.
- `Material` and `Stage Selection` are independent options. `Material` only uses the material count as a stopping condition and doesn't automatically navigate to stages that drop that material.
- `Use Originium` is only checked after `Use Sanity Potion`. Since MAA only uses Originium when no sanity potions remain, checking `Use Originium` will automatically set `Use Sanity Potion` to 999, ensuring all potions are used first.
- `Material` and `Stage` are independent options. `Material` is not going to automatically navigate to the stage for the specified material. You still need to manually configure the stage option.
- `Use Originium` will only be used after `Use Sanity Option`, because MAA will only use Originium to replenish sanity when there are no Sanity Potions left. Therefore, after checking `Use Originium`, MAA will lock the number of `Use Sanity Potion` to 999, making sure to consume all the Sanity Potions to avoid skipping the `Use Originium` judgment.
::: details Examples
::: details Example
| Use Sanity Potion | Use Originium | Perform Battles | Material | Result |
| :---------------: | :-----------: | :-------------: | :------: | ------ |
| | | | | Uses current sanity and stops. |
| 2 | | | | Uses current sanity, then uses sanity potions up to 2 times, then stops. |
| _999_ | 2 | | | Uses current sanity, then all sanity potions, then Originium up to 2 times, then stops. |
| | | 2 | | Runs the selected stage 2 times, then stops. |
| | | | 2 | Farms until 2 of the specified material are obtained, then stops. |
| 2 | | 4 | | Runs the selected stage up to 4 times, using up to 2 sanity potions if needed, then stops. |
| 2 | | | 4 | Farms until 4 of the specified material are obtained, using up to 2 sanity potions if needed, then stops. |
| 2 | | 4 | 8 | Runs the selected stage up to 4 times, using up to 2 sanity potions if needed. Stops early if 8 of the specified material are obtained before reaching 4 runs. |
| _999_ | 4 | 8 | 16 | Runs the selected stage up to 8 times, using all sanity potions and up to 4 Originium if needed. Stops early if 16 of the specified material are obtained before reaching 8 runs. |
| | 2 | | | Uses current sanity, then stops if any sanity potions are available. If no potions, uses up to 2 Originium. _Not MAA GUI behavior_ |
| 2 | 4 | | | Uses current sanity, then up to 2 sanity potions. If potions remain, stops; if no potions remain after using ≤2 potions, uses up to 4 Originium. _Not MAA GUI behavior_ |
| :------: | :----: | :------: | :------: | -------------------------------------------------------------------------------------------------------------------------------------- |
| | | | | Ends after using up the existing Sanity. |
| 2 | | | | Uses up the existing Sanity first, then consumes a Sanity Potion once, totalling `2` times. Ends after using up the Sanity. |
| _999_ | 2 | | | Uses up the existing Sanity and all Sanity Potions, then uses Originium, totalling `2` times. Ends after using up the Sanity. |
| | | 2 | | Ends after performing the selected stage `2` times. |
| | | | 2 | Ends after farming and obtaining `2` of the specified materials. |
| 2 | | 4 | | Ends after performing the selected stage `4` times, using up to `2` Sanity Potions. |
| 2 | | | 4 | Ends after farming and obtaining `4` of the specified materials, using up to `2` Sanity Potions. |
| 2 | | 4 | 8 | Ends after performing the selected stage `4` times, using up to `2` Sanity Potions. However, if `8` of the specified materials are obtained before completing `4` times, it will end early. |
| _999_ | 4 | 8 | 16 | Ends after performing the selected stage `8` times, using up all Sanity Potions and `4` Originium. However, if `16` of the specified materials are obtained before completing `8` times, it will end early. |
| | 2 | | | Uses up the existing Sanity first. If there are Sanity Potions in storage, it ends; if there are no Sanity Potions, it uses `2` Originium and ends after using up the Sanity. _Not a MAA GUI behavior_ |
| 2 | 4 | | | Uses up the existing Sanity first. If there are still some left after consuming `2` Sanity Potions, it ends; if there are no Sanity Potions after consuming ≤`2` Sanity Potions, it continues to use `4` Originium and ends after using up the Sanity. _Not a MAA GUI behavior_ |
:::
### Stage Selection
### Operations
- If your desired stage isn't in the selection menu, choose `Current/Last` in MAA, then manually navigate to the stage in-game.
Ensure you're on the stage details screen with the stage name and remaining sanity in the upper right and auto-deploy/start buttons in the lower right.
- If you're not on this screen, `Current/Last` will automatically enter the "last operation" stage shown on the bottom right of the terminal home screen.
- You can also enable `Manual entry of stage names` in `Task Settings` - `Sanity Farming` - `Advanced Settings` to manually input stage codes. Currently supported stages include:
- All main story stages. You can add `-NORMAL` or `-HARD` at the end to switch between normal and challenge modes.
- Resource stages like CE-6/LS-6 (LMD/EXP). Enter the exact code like `CE-6` or `LS-6`. MAA will automatically switch to level 5 if level 6 isn't available.
- Skill summary, voucher, and carbon stages (level 5 only). Enter exact codes like `CA-5`, `AP-5`, or `SK-5`.
- All chip stages. Enter complete stage codes like `PR-A-1`.
- For Annihilation mode, use these specific values:
- Current annihilation: Annihilation
- Chernobog: Chernobog@Annihilation
- Lungmen Outskirts: LungmenOutskirts@Annihilation
- Lungmen Downtown: LungmenDowntown@Annihilation
- If the stage you need is unavailable in the selection, please choose `Cur/Last` in MAA and manually locate the stage in the game.
Ensure the screen stays on the stage detail page with the **Start** and **Auto-Deploy** buttons available.
- If you are not on this page, `Cur/Last` will automatically navigate to the last stage played according to the record in the lower right corner of the terminal homepage.
- You can also enable `Manual entry of stage names` in `Combat` - `Advanced` and enter the stage number manually. Currently supported stages include:
- All main theme stages, where `-NORMAL` or `-HARD` can be added at the end to switch between standard and challenge modes.
- LMD stages and Battle Record stages 5/6. The input must be `CE-6` or `LS-6` even if you have not unlocked it yet. In that case, the program will automatically switch to the corresponding stage 5.
- Skill Summary, Shop Voucher, and Carbon Stages 5. The input also must be `CA-5`, `AP-5`, and `SK-5` respectively.
- Chip stages. The input must be complete with stage number, such as `PR-A-1`.
- Annihilation. The input must be `Annihilation`.
- Some side story stages, now contains `OF-1`, `OF-F3` and `GT-5`.
- The last three stages of the current SS event. This is available after downloading updates automatically from the [API](https://api.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json) when the event is on. The prompt will be shown on the main page when this is available.
- For the SS event rerun, you can enter `SSReopen-XX` to clear XX-1 ~ XX-9 levels once. Example `SSReopen-IC`.
- Side story stages like `OF-1`, `OF-F3`, and `GT-5`.
- The last three stages of the current Side Story event. These will be shown at the bottom of the interface after automatically downloading updates from the [API](https://api.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json).
- Rerun Side Story events: Enter `SSReopen-<stage prefix>` to farm all stages XX-1 through XX-9 in sequence, like `SSReopen-IC`.
::: details Example Screen
![Example Screen](/images/zh-cn/combat-start-interface-example.png)
::: details Example
![Example](/images/en-us/combat-start-interface-example.png)
:::
### Annihilation Mode
- MAA navigates to Annihilation using the button at the top-right of the terminal home screen. Ensure your selected Annihilation stage has unlocked `Full Delegation` and that you have enough `PRTS Annihilation Delegation Cards`.
- This feature is only recommended for stages where you've already achieved the 400-kill milestone.
- MAA will only navigate through the Annihilation button at the top right corner of the terminal homepage. Please ensure that the current Annihilation has unlocked `Full Delegation` and that you possess a sufficient number of "PRTS Proxy Annihilation Cards".
- After the current Annihilation refreshes or after reinstalling Arknights, returning from the Annihilation `Start Battle` page will automatically LSand `Intelligence Summary`. Please close this page in advance to prevent the task from getting stuck.
- It is only recommended for players who have already achieved "400 kills" in the current Annihilation to use MAA for automatic Annihilation.
## Advanced Settings
### Alternative Stages
### Alternative Stage
Alternative stages are selected based on daily stage availability - MAA will choose the first available stage in the list.
This functions like a schedule, not as a fallback if the primary stage selection fails.
The alternative stage is determined based on the availability of stages on the given day, i.e., the first available stage will be selected for battle.
This is a function similar to a schedule and cannot be used as a backup stage when the stage selection task fails.
1. Example: If primary stage is `CE-6/5` with alternatives `1-7` and `LS-6/5`:
- If `CE-6/5` is open today, MAA will run it and ignore the alternatives. If you haven't unlocked auto-deploy for CE-6/5, the task will fail.
- If `CE-6/5` is closed today, MAA will run `1-7` instead. If you haven't unlocked auto-deploy for 1-7, the task will fail.
- Since `1-7` is a permanent stage that appears before `LS-6/5` in the list, MAA will never run `LS-6/5` in this scenario.
2. If the primary stage is `Annihilation Mode`:
- Annihilation results won't affect the alternative stage logic - even if Annihilation fails, the task will continue.
- Alternative stages will only inherit the `Use Sanity Potion` and `Multiplier` settings, ignoring `Use Originium`, `Perform Battles`, and `Material` settings.
1. Example: Stage selection `CE-6/5`, alternatives `1-7` and `LS-6/5`:
- If `CE-6/5` is available on the day, it will proceed to `CE-6/5` and not to `1-7` or `LS-6/5`. If the player has not unlocked the `CE-6/5` mission node, the sanity farming task will fail.
- If `CE-6/5` is not available on the day, it will proceed to `1-7` and not to `CE-6/5`. If the player has not unlocked the 1-7 mission node, the sanity farming task will fail.
- Since `1-7` is a permanent stage before `LS-6/5`, MAA will never proceed to `LS-6/5` in this scenario.
2. If the stage selection is `Annihilation`, then:
- The selection logic of the remaining backup stages will not be affected by the result of the Annihilation, even if the Annihilation fails, the sanity farming task will not fail.
- The remaining backup stages will only inherit the settings of `Use Sanity Potion` and `Series`, and will not be controlled by `Use Originium`, `Perform Battles`, or `Material`.
### Remaining Sanity
This option activates after the main `Sanity Farming` task ends, ignoring all `Use Sanity Potion`, `Use Originium`, `Perform Battles`, `Material`, and `Multiplier` settings. It simply uses up any remaining sanity and stops.
It starts after the `Combat` task ends and is not controlled by `Use Sanity Potion`, `Use Originium`, `Perform Battles`, `Material`, or `Series`. It ends when the current remaining sanity is exhausted.
- Useful for farming a low-cost stage (like 1-7) with leftover sanity after your main stage becomes unaffordable.
- Also useful for automatically switching to single runs when you have insufficient sanity for your configured multiplier (e.g., if you set 1-7 for 6x runs but only have 30 sanity, it will automatically run five single 1-7 runs instead).
- The task will end if remaining sanity is insufficient (e.g., less than 6 sanity).
- If the selected remaining sanity stage is closed or unavailable, the task will fail.
- Suitable for clearing the remaining "corner" sanity (e.g., going to 1-7) after sanity is insufficient in the `Stage Selection` stage.
- Also suitable for automatically using single battles to use up sanity when the set number of consecutive battles is too high and sanity is insufficient (e.g., setting 1-7 to battle 6 times, but only having 30 sanity, thus automatically switching to 5 single battles of 1-7).
- If the remaining sanity is still insufficient, the task will end (e.g., less than 6 sanity).
- If the selected stage for remaining sanity is unopened, the sanity farming task will fail.
### Multiplier
### Series
MAA will use the specified battle multiplier setting:
MAA will fight according to the number of consecutive battles set by the user:
- **AUTO mode** (0):
- Automatically identifies and uses the maximum possible multiplier without wasting sanity
- Proceeds to the `Remaining Sanity` option afterward (if enabled)
- Automatically identify the maximum number of consecutive battles in the level, maintain the maximum number of consecutive battles and do not overflow sanity
- Enter the `Remaining Sanity` process after completion (if set)
- **Fixed value mode** (1-6):
- Uses exactly the specified multiplier
- If current sanity is insufficient for the set multiplier (e.g., only enough for 5× but set to 6×), ends the task and proceeds to `Remaining Sanity` (if enabled)
- **Numerical mode** (1~6):
- Perform consecutive battles according to the set number of times
- If the current sanity is not enough to complete the set number of times (such as only 5 times but set to 6 times), it will directly end the task and enter the `Remaining Sanity` process (if set)
- **Disabled mode** (-1):
- Doesn't change the in-game multiplier setting
- If sanity is insufficient for the current in-game multiplier setting, ends the task and proceeds to `Remaining Sanity` (if enabled)
### Perform Battles
MAA will run up to the specified number of battles.
Example: Assuming you have 100 sanity and the stage costs 6 sanity:
- If `Perform Battles` is 10 and multiplier is 4: MAA will do 2 runs × 4× multiplier = 8 battles (floor(10/4) × 4 = 8), using 48 sanity. It won't do another 4× run since that would be 12 battles, exceeding the set limit of 10.
- If `Perform Battles` is 10 and multiplier is AUTO: MAA will do one 6× run plus one 4× run = 10 battles (6 + 4 = 10), using 60 sanity.
- **Disable mode** (-1):
- Do not adjust the number of consecutive battles in the game
- If the sanity is not enough to complete the current set number of times in the game, directly end the task and enter the `Remaining Sanity` process (if set)
### Drop Recognition
- Automatically recognizes and counts material drops, uploading data to both [Penguin Statistics](https://penguin-stats.cn/) and [Yituliu](https://ark.yituliu.cn/).
- You can set a custom Penguin Statistics user ID if desired.
- Material drops are automatically recognized and printed to the program log. The data also gets uploaded to [Penguin Stats](https://penguin-stats.io/) and [Yituliu](https://ark.yituliu.cn/).
- You can manually set your Penguin Stats user ID in the settings.
## Error Handling
## Abnormal Detection
- Automatically checks `Auto Deploy` if it's available.
- Automatically reconnects and continues tasks after disconnections or the daily 4 AM server reset.
- Continues tasks after level-ups.
- If auto-deploy fails, abandons the current operation and retries the battle.
- `Auto-Deploy` will be automatically selected if not already in case you forget to do so.
- After disconnection or forced server reset at 4 am, it will automatically reconnect and continue to play the last stage selected in the game. If you need to cross the day, please check the last stage selection.
- An account level-up situation can be automatically handled as well as a failed operation in which case the operation will be abandoned and the battle will be retried.

View File

@@ -3,43 +3,45 @@ order: 9
icon: ph:sword-bold
---
# Auto Combat
# Copilot
Welcome to use and share operation files on [prts.plus](https://prts.plus).
::: warning
All features involving automatic combat require a stable game frame rate of at least 60 FPS, including but not limited to Auto Combat and Integrated Strategy.
::: important This page may be outdated.
:::
## Using Operations
You're welcome to share your tasks with [prts.plus](https://prts.plus)!
::: warning
All features involving auto-battle require a stable game frame rate of at least 60 frames, including but not limited to Copilot and Auto I.S..
:::
## Load Tasks
Supports automatic combat for any `Squad Formation Stage` and `Stationary Security Service` mode.
- This feature should be started from the squad selection screen where the `Start Operation` button is visible.
Then, import an operation by either `Import Local JSON Operation File` or `Enter Operation Code` in the upper left box of MAA.
- The `Auto Squad` feature will **clear the current squad** and automatically form a squad based on the operators required by the operation.
- You need to unmark any specially focused operators that will be used in the auto squad.
- You can add `custom operators` and `low-trust operators` to the auto squad as needed.
- You can disable `Auto Squad` and manually form the squad before starting if needed (for example, when using `Friend Support`).
- For "Paradox Simulation" stages, you must disable `Auto Squad`, manually select skills, and start automatic combat from the screen with the **Start Simulation** button.
- For "Stationary Security Service" stages, `Auto Squad` is ineffective. You must manually complete the **initial** task preparation until the screen with the **Start Deployment** button appears before starting automatic combat.
- You can set `Loop Times`, such as for Stationary Security Service. However, MAA will not borrow operators, so don't use this if you need to borrow operators.
- You can use the `Battle List` feature for automatic continuous combat across stages in the same area.
- The three buttons below the Battle List from left to right are `Batch Import`, `Add Stage`, and `Clear Stages`.
Right-clicking `Add Stage` adds a challenge mode stage; right-clicking `Clear Stages` clears all unchecked stages.
- After importing an operation, the stage name will appear below the battle list. Confirm it's correct before adding the stage. You can drag stages to reorder them and check/uncheck to control execution.
- When using this feature, start automatic combat from the **map screen where the stages are located**. The automatic combat queue will stop if sanity is insufficient, combat fails, or you don't achieve three stars.
- Ensure all stages in the list are in the same area (navigable by swiping the map screen left or right).
- **Please remember to like high-quality operations to boost their ratings and encourage their creators.**
- Please run it on the screen with the `Start Operation` button.
Then, import the task by `Import Local JSON Task File` or `Enter Task Station Secret Code` in the upper left box of MAA.
- The `Auto Squad` feature will **clear the current squad** and automatically form a squad based on the operators required for the task.
- You need to cancel the special focus on the operators for Auto Squad.
- You can add `custom operators` and `low-trust operators` for auto squad formation as needed.
- You can disable `Auto Squad` and manually form the squad before starting if you need to use `Friend Support` or for other personal preferences.
- For "Paradox Simulation" stages, you must disable `Auto Squad`, manually select skills, and start automatic combat on the screen with the **Start Simulation** button.
- For "Stationary Security Service" stages, `Auto Squad` is ineffective. You must manually complete the **initial** task preparation until the **Start Deployment** button appears on the stage details screen to start automatic combat.
- You can set `Loop Times`, such as for Stationary Security Service. However, MAA will not borrow operators. Do not use this feature if you need to borrow operators.
- You can use the `Battle list` feature for automatic continuous combat in the same area stages.
- The three buttons below the Battle list from left to right are `Batch Import`, `Add Stage`, and `Clear Stages`.
Right-click `Add Stage` to add a raid stage, and right-click `Clear Stages` to clear unchecked stages.
- After importing the task, the stage names will appear below the battle list. Confirm they are correct before adding the stage. You can drag and adjust the order of the stages in the list and check whether to execute them.
- After enabling this feature, start automatic combat on the **map screen where the stages are located**. The automatic combat queue will stop if sanity is insufficient, combat fails, or the settlement is not three stars.
- Ensure that the stages in the list are in the same area (can be navigated by swiping the map screen left or right).
- Remember to like the tasks that you found helpful!
![image](/images/zh-cn/copilot-click-like.png)
## Creating Operations
## Create Tasks
- Please use the [Operation Editor](https://prts.plus/create) to create operations. You can refer to the [Combat Operation Protocol](../../protocol/copilot-schema.md) for guidance.
- Getting map coordinates:
- After entering the stage name in the Operation Editor, a draggable and zoomable coordinate map will automatically load in the lower left corner, where you can click to set operator positions.
- If you export the JSON after entering the stage name and then start an operation, a map image with coordinate information will be generated in the `debug\map` folder in your MAA directory.
- Use [PRTS.Map](https://map.ark-nights.com/areas) and change the `Coordinate Display` to `MAA` in settings.
- Practice plans are supported.
- We recommend including your name (as author), reference video links, and other helpful information in the operation description.
- You're welcome to join the QQ group [1169188429](https://jq.qq.com/?_wv=1027&k=QZcGcJ9G) to discuss operation creation and related topics.
- Please use the [Task Editor](https://prts.plus/create) to create tasks. A tool for creating tasks is provided in the directory of MAA. See also: [Copilot Schema](../../protocol/copilot-schema.md) for help.
- Get map coordinates
- After filling in the stage in the Task Editor, a draggable and zoomable coordinate map will automatically load in the lower left corner, where you can click to set the current operator positions.
- Start an operation after filling in `stage_name`. A file under `debug\map` named `map.png` will be generated for your reference.
- Refer to [PRTS.map](https://map.ark-nights.com/), with the `coordinates` set to `MAA` mode.
- Drill plan is available for testing.
- It is recommended to write your name, video walkthrough URL, or other things that you think are helpful in the description.

View File

@@ -5,13 +5,15 @@ icon: solar:shop-2-bold
# Credit Store
- Automatically visits friends to obtain credit points and shops at the credit store.
- Support for earning credits through combat:
- MAA will use a support operator to clear the `OF-1` stage from Heart of Surging Flame. Please ensure this stage is unlocked.
- This feature won't activate when the stage selection is set to `Current/Last`.
::: important This page may be outdated.
:::
- Automatically visit friends to obtain credit points and go to the credit store for shopping.
- With the help of combat credit:
- Use a support operator to clear the `OF-1` stage in Heart of Surging Flame. If the stage is not unlocked, please do not select this option.
- It does not take effect when the stage selection is set to `Cur/Last`.
## Advanced Settings
- Both priority purchase items and blacklist use keyword matching. For example, entering `Carbon` will match both `Carbon Stick` and `Carbon Brick`.
- You can use either English semicolons `;` or Chinese semicolons `` as separators.
- When `Stop purchasing items when credits are below 300` is enabled, priority purchase items will still be bought even when below 300 credits.
- Whitelist and Blacklist are keyword matches, for example, filling in `碳` (Carbon Stick) will match `碳` (Carbon Stick) and `碳素` (Carbon Brick). May still require only the original Chinese as input.
- `Stop purchasing items when credits are below 300` will still purchase whitelist items even when below 300.

View File

@@ -3,34 +3,29 @@ order: 4
icon: material-symbols:view-quilt-rounded
---
# Base Management
# Base
## Normal Mode
::: important This page may be outdated.
:::
### Shift Strategy
## Workshift Strategy
- Automatically calculates and selects the **optimal solution within a single facility**, supporting all generic skill combinations and special skill synergies.
- Automatically identifies EXP Records, Gold Bars, Originium Shards, and Chips, deploying appropriate operator combinations for each.
- Automatically uses drones according to the selected `Drone Usage` setting.
- Automatically detects morale levels and assigns operators with remaining morale percentage below the `Base Facility Morale Threshold` to dormitories.
- Automatically calculate and choose the **optimal solution within a single facility**. Supports all general and special skill combinations.
- Supports recognition of Battle Record, Pure Gold, Originium Shard, Chip and so on for different operators.
- Automatically use drones according to the selected `drone usage`.
- Recognizes the percentage of the Morale bar. When Morale is below some threshold, the operator will be moved to the dormitory.
### Additional Notes
## Note
- Base shift management currently optimizes for single-facility efficiency, not cross-facility global optimization.
- Recognizable and usable examples: `Shamare + Tequila`, `Vermeil + Scene`.
- Unrecognizable examples: `Rosmontis System`, `Pinus Sylvestris Knights`.
- When `Drone Usage` is set to `Trading Post - LMD`, the `Shamare Group` will be prioritized.
- Reception Room selects operators with corresponding clue affinity when only one clue type is missing; otherwise selects generic operators.
- Reception Room only sends clues when your collection is full, and sends only three at a time. To customize the number sent, modify the `ClueSelected` - `maxTimes` field in `resource/tasks/tasks.json` in the MAA directory.
- Enabling `Do not place stationed operators in dormitory` prevents operators like `Irene` and `Logos` from being assigned to dormitories when not training in the Training Room, but also prevents operators with low morale in the Processing Station from being moved to dormitories.
- Control Center strategy is complex; currently only considers `Amiya`, `Swire`, `Kal'tsit`, `Team Rainbow`, and other operators with +0.05 morale bonus. This will be gradually optimized.
- You can select which facility types MAA should manage (all are selected by default).
- The work shift strategy is based on the optimal solution within a single facility instead of multiple facilities. Combinations such as: `Shamare-Tequila`, `Vermeil-Scene` within a single facility can be recognized correctly; while combinations like `Rosmontis`, `Pinus Sylvestris` among facilities are not supported yet.
- If `Usage of Drone` is selected with the option `Trading Post-LMD`, it will recognize `Shamare` and reserve it for her.
- Operators of the corresponding faction will be selected when only one Clue is needed in the Reception Room; otherwise, general operators will be chosen.
- The reception Room will send out Clues only when your Clues are full. Three Clues will be sent out at most. If wanted, you can edit the number of sent Clues in the `ClueSelected` - `maxTimes` field in `resource/tasks/tasks.json`.
- If you do not want operators like `Irene` or someone else to be put into the dormitory when the training room is not in use, you can switch off `Working operator shall not be put into the dormitory` in the settings. Note that this may cause the operators with non-full fatigue to not enter the dormitory as well.
- Due to the complexity of the Control Center, only `Amiya`, `Swire`, `Kal'tsit`, `Team Rainbow` and other Morale+0.05 operators will be considered. To be improved in future.
- Some alternate operators may have conflicts in Infrastructure. Please take note if there are "Operator conflict" warnings on the UI, and double check the Infrastructure to shift manually (e.g. some facilities may not have any operator).
- You can choose the facility categories that need to be handled by MAA, with all selected by default.
## Preset Rotation Mode
## Custom infrastructure shift change (Beta)
- This mode requires preset squads configured in-game. MAA will automatically rotate through them.
## Custom Base Mode
- The [Schedule Generator](https://ark.yituliu.cn/tools/schedule) created by community experts can help you create custom schedules. Refer to the [Base Facility Protocol Documentation](../../protocol/base-scheduling-schema.md) for usage.
- The MAA folder `/resource/custom_infrast/` contains built-in theoretically maximum-efficiency presets. Not recommended for direct use due to their extreme operator and elite/skill level requirements.
- Several sets of extremely efficient tasks are built-in under the MAA folder `/resource/custom_infrast/`, which can be used as a reference. Due to its high requirements for operators and their levels, it is not recommended for direct use.

View File

@@ -3,59 +3,59 @@ order: 7
icon: ri:game-fill
---
# Auto Integrated Strategy
# Integrated Strategy (I.S.)
MAA selects the latest theme by default, which can be changed in `Auto Integrated Strategy` - `Integrated Strategy Theme`.
::: important This page may be outdated.
:::
MAA selects the latest theme by default, and can be changed in `Auto I.S.` - `General`.
::: warning
All features involving automatic combat require a stable game frame rate of at least 60 FPS, including but not limited to Auto Combat and Integrated Strategy.
All features involving auto-battle require a stable game frame rate of at least 60 frames, including but not limited to Copilot and Auto I.S..
:::
- Please pin the corresponding Integrated Strategy theme at the terminal in-game. Although automatic navigation is currently possible, long-term functionality is not guaranteed.
- Please manually end explorations of **non-target themes** in advance to ensure the target theme is ready to start exploration.
- You can select theme, difficulty, squad, starting operator (single operator name only), and more in settings.
- MAA can use support operators to start, by first entering the target operator name in `General Settings``Starting Operator` and then enabling `Advanced Settings``Use support unit for "Starting Operator"`.
- When playing for the **first time** in a newly installed client:
- The difficulty selection button will not be displayed. Please manually select a difficulty once in-game, after which MAA can select it automatically.
- Tutorials will appear after entering the map screen. Please read and close them manually.
- Please pin the corresponding I.S. theme to the terminal of the game. Although automatic navigation is currently available, long-term usability is not guaranteed.
- If there is an exploration of non-target themes (such as if you plan to use MAA to auto Mizuki, but there is still an unfinished exploration of Phantom), please end it manually.
- MAA will not automatically select the difficulty. If the difficulty is not selected, it will get stuck/repeatedly enter and exit the difficulty selection interface.
- In the settings, you can choose the team, starting operator (only one operator name), etc.
## Recommended Starts
## Recommended Starting Strategies
::: details _Last updated 2025/8/2_
MAA can start with a support operator, which need to enable the option `Auto I.S.``Advanced``Select "Starting Operator" from support unit list`.
| Theme | Difficulty | Squad | Strategy | Operator |
| ------- | ----------------- | --------------------------------------- | ------------------------- | --------- |
| Phantom | Formal Investigation·3~7 | Leader Squad / Tactical Assault Squad | Overcoming Your Weaknesses | Thorns |
| Mizuki | Surging Waves·3~7 | People-Oriented Squad / Mind Over Matter Squad | Slow and Steady Wins the Race | Wiš'adel |
| Sami | Braving Nature·4~10 | Special Training Squad / Tactical Ranged Squad | Slow and Steady Wins the Race | Wiš'adel |
| Sarkaz | Face the Spirit·4~10 | Blueprint Mapping Squad / Tactical Ranged Squad | Slow and Steady Wins the Race | Wiš'adel |
| Garden | Enter the Garden·3~10 | Leader Squad / Tactical Ranged Squad | Slow and Steady Wins the Race | Wiš'adel |
::: details
The recommended difficulties consider factors like `enemy difficulty`, `hope consumption`, and `score multiplier`, and have been tested to be stable with high-level operators. Feel free to adjust based on your situation and needs.
| Theme | Difficulty | Squad | Strategy | Operators |
| ------- | -------------------- | ----------------------------------------------- | ----------------------------- | --------------------- |
| Phantom | Formal Investigation | Leader Squad / Tactical Assault Squad | Overcoming Your Weaknesses | Thorns |
| Mizuki | Surging Waves·3 | People-Oriented Squad / Mind Over Matter Squad | Overcoming Your Weaknesses | Gavial the Invincible |
| Sami | Braving Nature·4 | Special Training Squad / Tactical Ranged Squad | Slow and Steady Wins the Race | Wiš'adel |
| Sarkaz | Face the Spirit·4 | Blueprint Mapping Squad / Tactical Ranged Squad | Slow and Steady Wins the Race | Wiš'adel |
| Theme | Notes |
| ------- | ----- |
| Phantom | `Formal Investigation·4` and higher difficulties may give hope-reducing collectibles at start, preventing recruitment of six-star operators. |
| Mizuki | `Surging Waves·4` and higher difficulties increase six-star operator hope cost by +1, making it potentially impossible to recruit them with `Mind Over Matter Squad`.<br>`People-Oriented Squad` is better for high-level accounts, while `Mind Over Matter Squad` requires luck. |
| Sami | `Braving Nature·6` and higher difficulties increase six-star operator hope cost by +1, potentially making it impossible to recruit them with `Special Training Squad`. |
| Sarkaz | `Face the Spirit·15` and higher difficulties increase six-star operator hope cost by +1, potentially making it impossible to recruit them with `Blueprint Mapping Squad`.<br>With `Blueprint Mapping Squad`, MAA will adopt an avoidance strategy to quickly obtain `Spirit Bookmarks`, but generally cannot complete endings.<br>When using the Originium Ingot farming strategy with `Point-Stab Ingot Squad`, MAA will use shop refreshing to speed up the process. |
| Garden | `Enter the Garden·15` and higher difficulties increase six-star operator hope cost by +1, potentially making it impossible to recruit them with `Leader Squad`.<br>When set to `Enter the Garden·3` difficulty with the Originium Ingot farming strategy and `Leader Squad`, MAA will use the `End of Time` stage-skip strategy to speed up the process. |
The recommended difficulty level is the one without the `Enemy Difficulty` and `Desired Consumption` bonuses. It is relatively stable when tested at a high level and can be adjusted freely according to actual conditions and needs.
| Theme | Notes |
| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Phantom | In the `Face the Disaster` difficulty, you may obtain a collection that will deduct your hopes, resulting in the inability to recruit six-star operators at the beginning of the game. |
| Mizuki | The cost of recruiting six-star operators in `Surging Waves·4` and higher difficulties is increased by 1. It may be impossible to recruit six-star operators when using `Mind over Matter Squad` at the beginning.<br>`People-Oriented Squad` work best with People-Oriented; `Mind Over Matter` Squad requires a bit of luck. |
| Sami | The cost of recruiting six-star operators in `Braving Nature·5` and higher difficulties is increased by 1. It may be impossible to recruit six-star operators when using `Special Training Squad` at the beginning. |
| Sarkaz | The cost of recruiting six-star operators in `Face the Spirit·5` and higher difficulties is increased by 1. It may be impossible to recruit six-star operators when using `Blueprint Mapping Squad` at the beginning.<br>Selecting the `Blueprint Mapping Squad` results in a completely stealth-oriented strategy, means that it is basically impossible to pass the ending. |
:::
## Combat Strategy
## Battle Strategy
All MAA operations in Integrated Strategy use preset strategies, with all combat stages using built-in operation files. When no operation exists for a specific stage, a basic (not very intelligent) decision tree handles combat.
All operations in automatic Integrated Strategy are pre-set strategies, and all stage battles use built-in job files. When the corresponding mission for the level does not exist, a general decision tree, which is not very smart, will be used for the battle.
For details, see the [Integrated Strategy Protocol](../../protocol/integrated-strategy-schema.md).
For more details, please refer to the [Integrated Strategy Schema](../../protocol/integrated-strategy-schema.md).
- Automatically recognizes operators and their levels, selecting optimal operators and skills.
- Recognizes shop items and prioritizes purchasing more powerful collectibles.
- It supports automatic recognition of operators and proficiency and automatically selects better operators and skills.
- It supports identifying store items and prioritizes purchasing more powerful relics.
## Exception Handling
## Abnormal Detection
- Automatically reconnects and continues tasks after disconnections or the 4 AM server reset.
- For battles exceeding 5 minutes, automatically retreats all ground units; after 6 minutes, abandons the battle to avoid time-consuming deadlocks.
- If a task encounters problems, automatically abandons the current exploration and retries.
- It supports reconnection after disconnection and supports continuation to auto after 4 a.m. server reset.
- Encounters longer than 5 minutes will automatically retreat all ground units, and longer than 6 minutes will automatically abandon the operation to avoid wasting time/getting stuck.
- If the exploration gets stuck, it will automatically abandon and retry.
If the program repeatedly gets stuck at the same point, please submit an Issue with logs
However, if it often gets stuck in a certain place and then gives up, seriously affecting efficiency, please feel free to submit an issue for feedback.

View File

@@ -5,38 +5,45 @@ icon: icon-park-solid:other
# Others
## GPU-Accelerated Inference
::: important This page may be outdated.
:::
Uses DirectML to call the GPU for recognition inference acceleration<sup>[PR](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/9236)</sup>, reducing CPU usage significantly with minimal GPU usage. Recommended to enable.
## GPU-accelerated inference
Testing has shown that some graphics cards may experience recognition issues when using this feature due to missing functionality or lower performance. MAA has built-in a blacklist for certain GPUs<sup>[PR1](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/9990)[PR2](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/12134)</sup>. If you encounter recognition issues with GPUs not on the blacklist after enabling this feature, please submit an Issue.
Use DirectML to call the GPU for recognition and inference acceleration.<sup>[PR](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/9236)</sup>It can reduce a significant amount of CPU usage with minimal GPU usage, and it's recommended to enable it.
## One-Time Only
Testing has shown that some graphics cards may encounter recognition issues when using this feature due to lacking certain functions or having lower performance. MAA has already built-in a blacklist for some GPUs.<sup>[PR](https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/9990)</sup>If graphics cards not on the list also encounter recognition issues after enabling this feature, please submit an issue.
Configuration changes in the main interface and settings are usually saved automatically, but the following will reset after MAA restarts:
## Only Once
- Options marked with an `*`
- Options marked with `(One-time only)`
- Half-selected checkboxes obtained by right-clicking
Configuration changes in the main interface and settings are usually saved automatically, but the following types will reset after MAA is restarted.
## Auto-Switch Configuration at Startup
- Options marked with a `*`
- Options marked with `(Only Once)`
- Semi-selected switches obtained by right-clicking the checkbox
MAA supports automatically switching configurations via launch parameters by adding `--config <configuration name>` after the MAA process name. Example: `./MAA/MAA.exe --config Official`.
## Automatically switch configurations on startup
Some characters need to be escaped according to JSON conventions. Example: when the configuration name is `"Official"`, the parameter should be `--config \"Official\"`.
MAA supports automatic configuration switching through launch parameters by appending `--config <configuration name>` after the MAA process name.
Example: `./MAA/MAA.exe --config Official`.
## Start/End Scripts
Some symbols need to be escaped, following Json conventions.
Example: when the configuration name is `"Official"`, the parameter should be `--config \"Official\"`.
Since v4.13.0, MAA supports setting scripts to run before starting and after finishing tasks. Enter the absolute or relative path to a batch file (`.bat`) in the input field.
## Pre/Post-Script
Starting from v4.13.0, it is possible to set pre/post-script that automatically executes batch files before and after the task.
You need to provide the absolute or relative path to the batch file, which should have a `.bat` extension.
## Configuration Migration
In the Windows version, all MAA configurations are stored in `gui.json` inside the `config` folder. Migrating this folder transfers all MAA settings.
In the Windows version, all MAA configurations are stored in the `gui.json` file within the `config` folder. Migrating this folder will transfer all MAA settings.
## Additional Notes
## Note
- Tasks on the left side of the main page can be dragged to change their order, as can facilities in the base management settings.
- All click operations target random positions within buttons, following a Poisson distribution (higher probability at the center, decreasing with distance from center).
- The core algorithms are developed in C++ with multi-level caching to minimize CPU and memory usage.
- The software supports automatic updates ✿✿ ヽ(°▽°). We recommend non-critical users try the beta version, which typically updates faster and has fewer bugs. (What MIUI? (╯‵□′)╯︵┻━┻)
- If automatic downloads fail for new versions, you can manually download the OTA package and place it in the MAA directory for automatic updating.
- Tasks order can be changed on the UI. So can the shifting order in the infrastructure.
- All clicking event is randomized within a region, following Poisson distribution (higher probability at the center, lower probability around).
- Developed in C++, the core algorithm supports multi-level cache, to reduce CPU and memory usage as much as possible.
- Our software supports auto-update ✿✿ ヽ(°▽°) Beta-testers can try beta versions, which update faster and less buggy (maybe).
- If auto-update fails, you can download the OTA package manually and put the ZIP file under the same directory. The update will start automatically.

View File

@@ -3,19 +3,22 @@ order: 8
icon: solar:streets-map-point-linear
---
# Reclamation Algorithm
# Reclamation Algorithm (R.A.)
Currently, support for Reclamation Algorithm is still in early stages and unattended operation is not recommended, as stability cannot be guaranteed at this time.
::: important This page may be outdated and not yet implemented for Global.
:::
Currently, the support for Reclamation Algorithm is still in the early stages, and it is not recommended to run it unattended. Stability cannot be guaranteed at this stage.
## Default Mode
1. You need to start the task from the Reclamation Algorithm main interface (navigation not yet implemented)
2. Cannot be used when you already have an existing save file (delete the existing save to use)
3. Cannot be used when operators are present in the Reclamation Algorithm squad (clear the current squad, especially after completing a wave)
1. You need to start the task on the main interface of R.A.. (navigation is not yet written)
2. Cannot be used if there is already a save file. (just delete the existing save file)
3. Cannot be used if there are operators in the R.A. squad. (just clear the current squad in R.A., especially after finishing a wave)
## Manufacturing Points Farm
## Points farm through crafting
1. You need to start from the page where you can see the base camp after entering Reclamation Algorithm
2. If no item name is specified, Glow Sticks will be crafted by default
3. Prerequisite: It must be the first day after settlement, with no enemy raids entering the base camp for the next three days
4. If the manufacturable quantity is exactly a multiple of 99, the process may get stuck. You can use up a small amount before saving; this issue will be fixed in the future
1. You need to start on the page where you can see the base camp after entering R.A..
2. If the item name is not filled in, the default is to craft Glow Sticks.
3. Prerequisite: It is the first day after settlement, and no enemy raids are entering the base camp for the next three days.
4. If the number that can be manufactured is exactly a multiple of 99, it will get stuck. You can use up a bit before saving, this will be fixed later.

View File

@@ -3,18 +3,21 @@ order: 2
icon: fluent:people-24-filled
---
# Recruitment
# Recruit
Auto Recruitment and [Recruitment Recognition](./tools.md#recruitment-recognition) are two different features!
::: important This page may be outdated.
:::
## Auto Recruitment
The Recruit option in the 'Farming' tab and [recruitment recognition](./tools.md#recruitment-recognition) are two different features, though most options from the tool are in the recruit option as well.
Supports automatic use of `Expedited Plans`, allows setting maximum recruitment times per task, and can be combined with `Auto use Expedited Plans` to quickly use up all recruitment permits.
## Auto-recruitment
Pop-up notifications will appear when 1★, 5★, or 6★ tags are detected.
Auto-recruitment supports using `Expedited Plan` to make it fully automated. Please enable `Auto use Expedited Plan` and modify `Recruit max times` in `Recruit` - `General`.
Recruitment tag data is automatically uploaded to [Penguin Statistics](https://penguin-stats.io/) and [Yituliu](https://ark.yituliu.cn/) when refreshing recruitment.
Pop-up notification when 1★, 5★, 6★ operators are recruited.
Auto-uploading recruitment data to [Penguin Stats](https://penguin-stats.io/) and [Yituliu](https://ark.yituliu.cn/) while auto-recruitment.
## Advanced Settings
`Auto confirm` means MAA automatically selects tags and performs recruitment, while `Manual confirm` means no automatic tag selection or recruitment is performed.
`Auto confirm` means MAA automatically selects tags and recruits, while `Manually confirm` means no automatic selection and recruitment.

View File

@@ -5,6 +5,9 @@ icon: lucide:gift
# Rewards
Automatically claims daily rewards and weekly rewards.
::: important This page may be outdated.
:::
Automatically claim daily rewards and weekly rewards.
Other reward types are also supported, please check the settings for details.

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