diff --git a/.devcontainer/Dockerfile b/.devcontainer/0/Dockerfile similarity index 81% rename from .devcontainer/Dockerfile rename to .devcontainer/0/Dockerfile index 58ea211b70..6158289f3a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/0/Dockerfile @@ -17,11 +17,12 @@ RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh - # Configure conda environment RUN eval "$(conda shell.bash hook)" \ - && conda create -n maa python=$PYTHON_VERSION -y \ + && conda create -n maa \ && conda activate maa \ - && conda install -y conda-forge::nodejs=$NODEJS_VERSION \ - && pip install pre-commit black \ - && npm install -g pnpm + && conda install -y \ + python=$PYTHON_VERSION \ + conda-forge::nodejs=$NODEJS_VERSION \ + && pip install pre-commit black isort # Finalize conda setup RUN conda init \ diff --git a/.devcontainer/0/devcontainer.json b/.devcontainer/0/devcontainer.json new file mode 100644 index 0000000000..0d9cce0f18 --- /dev/null +++ b/.devcontainer/0/devcontainer.json @@ -0,0 +1,64 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node +{ + "name": "MAA Docs Env (Light)", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + // "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "build": { + "dockerfile": "Dockerfile" + }, + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3001], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "bash .devcontainer/0/post-create.sh", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "nekosu.maa-support", + "ms-python.python", + "ms-python.black-formatter", + "ms-python.isort", + "esbenp.prettier-vscode", + "DavidAnson.vscode-markdownlint", + "yzhang.markdown-all-in-one", + "vue.volar", + "mkxml.vscode-filesize" + ], + "settings": { + // Editor formatting + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + + // Language-specific formatting + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + } + }, + + // Python formatting and linting + "isort.args": ["--profile", "black"], + + // Python runtime + "python.terminal.launchArgs": ["-u"], + "python.defaultInterpreterPath": "/home/vscode/miniconda/envs/maa/bin/python", + "python.terminal.activateEnvironment": false, + + // Performance optimizations + "search.exclude": { + "**/node_modules": true, + "**/3rdparty": true + } + } + } + } + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.devcontainer/post-create.sh b/.devcontainer/0/post-create.sh similarity index 63% rename from .devcontainer/post-create.sh rename to .devcontainer/0/post-create.sh index a2aa336b6a..7827ebaac7 100644 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/0/post-create.sh @@ -4,18 +4,13 @@ WORKSPACE=$(pwd) # conda activate maa echo "====================" -echo "Setting up git safe.directory for $WORKSPACE and its submodules..." cd "$WORKSPACE" +echo "Setting up git safe.directory for $WORKSPACE and its submodules..." git config --global --add safe.directory "$WORKSPACE" git submodule foreach --recursive 'git config --global --add safe.directory "$toplevel/$path"' echo "====================" -cd "$WORKSPACE" -echo "Installing dependencies for python..." -# pip install -r tools/.../requirements.txt -# pip install -r tools/.../requirements-dev.txt - -echo "====================" -echo "Installing dependencies for nodejs..." cd "$WORKSPACE"/docs +echo "Installing node modules..." +npm install -g pnpm pnpm install --frozen-lockfile diff --git a/.devcontainer/1/Dockerfile b/.devcontainer/1/Dockerfile new file mode 100644 index 0000000000..91f4b22161 --- /dev/null +++ b/.devcontainer/1/Dockerfile @@ -0,0 +1,39 @@ +FROM mcr.microsoft.com/devcontainers/base:ubuntu + +USER vscode + +ENV CONDA_DIR=/home/vscode/miniconda +ENV PATH="$CONDA_DIR/bin:$PATH" + +ARG CLANGD_VERSION=20 +ARG PYTHON_VERSION=3.12 +ARG NODEJS_VERSION=24 + +# Install system dependencies +RUN sudo apt update \ + && sudo apt upgrade -y \ + && sudo apt install -y \ + cmake clangd-${CLANGD_VERSION} + +RUN sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-${CLANGD_VERSION} 100 + +# Install Miniconda +RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh \ + && bash ~/miniconda.sh -b -p ${CONDA_DIR} \ + && rm ~/miniconda.sh \ + && conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main \ + && conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r + +# Configure conda environment +RUN eval "$(conda shell.bash hook)" \ + && conda create -n maa \ + && conda activate maa \ + && conda install -y \ + python=${PYTHON_VERSION} \ + conda-forge::nodejs=${NODEJS_VERSION} \ + && pip install pre-commit black isort + +# Finalize conda setup +RUN conda init \ + && conda config --set auto_activate false \ + && echo "conda activate maa" >> ~/.bashrc diff --git a/.devcontainer/1/devcontainer.json b/.devcontainer/1/devcontainer.json new file mode 100644 index 0000000000..4e205dc160 --- /dev/null +++ b/.devcontainer/1/devcontainer.json @@ -0,0 +1,83 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node +{ + "name": "MAA Core Env (Full)", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + // "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "build": { + "dockerfile": "Dockerfile" + }, + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3001], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "bash .devcontainer/1/post-create.sh", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "nekosu.maa-support", + "ms-vscode.cmake-tools", + "xaver.clang-format", + "llvm-vs-code-extensions.vscode-clangd", + "ms-python.python", + "ms-python.black-formatter", + "ms-python.isort", + "esbenp.prettier-vscode", + "DavidAnson.vscode-markdownlint", + "yzhang.markdown-all-in-one", + "vue.volar", + "mkxml.vscode-filesize" + ], + "settings": { + // Editor formatting + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + + // Language-specific formatting + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + } + }, + "[cpp]": { + "editor.defaultFormatter": "xaver.clang-format" + }, + "[c]": { + "editor.defaultFormatter": "xaver.clang-format" + }, + + // Python formatting and linting + "isort.args": ["--profile", "black"], + + // Python runtime + "python.terminal.launchArgs": ["-u"], + "python.defaultInterpreterPath": "/home/vscode/miniconda/envs/maa/bin/python", + "python.terminal.activateEnvironment": false, + + // CMake settings + "cmake.configureSettings": { + "BUILD_DEBUG_DEMO": "ON", + "CMAKE_TOOLCHAIN_FILE": "MaaDeps/cmake/maa-x64-linux-toolchain.cmake" + }, + "cmake.configureOnOpen": false, + + // Performance optimizations + "search.exclude": { + "**/node_modules": true, + "**/build": true, + "**/install": true, + "**/MaaDeps": true, + "**/3rdparty": true + } + } + } + } + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.devcontainer/1/post-create.sh b/.devcontainer/1/post-create.sh new file mode 100644 index 0000000000..8d1a355e83 --- /dev/null +++ b/.devcontainer/1/post-create.sh @@ -0,0 +1,42 @@ +#!/bin/bash +WORKSPACE=$(pwd) + +# conda activate maa + +echo "====================" +cd "$WORKSPACE" +echo "Setting up git safe.directory for $WORKSPACE and its submodules..." +git config --global --add safe.directory "$WORKSPACE" +git submodule foreach --recursive 'git config --global --add safe.directory "$toplevel/$path"' + +echo "====================" +cd "$WORKSPACE"/docs +echo "Installing node modules..." +npm install -g pnpm +pnpm install --frozen-lockfile + +echo "====================" +cd "$WORKSPACE" +echo "Installing Python dependencies..." +# Install Python dependencies from all tools +for req_file in tools/*/requirements.txt; do + if [ -f "$req_file" ]; then + echo "Installing from $req_file" + pip install -r "$req_file" + fi +done + +for req_file in tools/*/requirements-dev.txt; do + if [ -f "$req_file" ]; then + echo "Installing from $req_file" + pip install -r "$req_file" + fi +done + +echo "====================" +cd "$WORKSPACE" +echo "Installing MaaDeps..." +python tools/maadeps-download.py +# Link clang-format & clangd to /usr/local/bin for easy access +sudo ln -s $WORKSPACE/MaaDeps/x-tools/llvm/bin/clang-format /usr/local/bin/clang-format +# sudo ln -s $WORKSPACE/MaaDeps/x-tools/llvm/bin/clangd /usr/local/bin/clangd diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2d4e6eeede..b5c5908b5a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,50 +1,5 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node { - "name": "MAA", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - // "image": "mcr.microsoft.com/devcontainers/base:ubuntu", - "build": { - "dockerfile": "Dockerfile" - }, - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [3001], - - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "bash .devcontainer/post-create.sh", - - // Configure tool-specific properties. - "customizations": { - "vscode": { - "extensions": [ - "mkxml.vscode-filesize", - "nekosu.maa-support", - "DavidAnson.vscode-markdownlint", - "esbenp.prettier-vscode", - "vue.volar", - "ms-python.python", - "ms-python.black-formatter" - ], - "settings": { - // format - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", - "[markdown]": { - "editor.defaultFormatter": "DavidAnson.vscode-markdownlint" - }, - "[python]": { - "editor.defaultFormatter": "ms-python.black-formatter" - }, - // python - "python.terminal.launchArgs": ["-u"], - "python.defaultInterpreterPath": "/home/vscode/miniconda/envs/maa/bin/python", - "python.terminal.activateEnvironment": false - } - } - } - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" + "name": "Plain Env (Nothing Installed)", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "postCreateCommand": "git config --global --add safe.directory \"$(pwd)\" && git submodule foreach --recursive 'git config --global --add safe.directory \"$toplevel/$path\"'" } diff --git a/.gitattributes b/.gitattributes index 0dc3ac63d6..4acc27b030 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,3 +10,5 @@ *.md text eol=lf *.yml text eol=lf *.yaml text eol=lf + +*.sh text eol=lf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 728cd9e8de..736d12d57f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,36 +4,50 @@ ci: autofix_prs: true repos: - repo: https://github.com/shssoichiro/oxipng - rev: v9.1.4 + rev: v9.1.5 hooks: - id: oxipng + name: Image Compression args: ["-q", "-o", "2", "-s", "--ng"] - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v20.1.0 + rev: v21.1.1 hooks: - id: clang-format + name: Clang-Format (MaaCore) files: ^src/MaaCore/.* args: ["--assume-filename", ".clang-format"] - repo: https://github.com/rbubley/mirrors-prettier - rev: v3.5.3 + rev: v3.6.2 hooks: - id: prettier - name: prettier (config files) + name: Prettier (Config Files) files: ^((\.github/ISSUE_TEMPLATE|resource|src|tools)/.*|\.pre-commit-config\.yaml|package-definition\.json) types_or: - yaml - json - repo: https://github.com/rbubley/mirrors-prettier - rev: v3.5.3 + rev: v3.6.2 hooks: - id: prettier - name: prettier (docs) + name: Prettier (Documentation) files: ^docs/.* + - repo: https://github.com/psf/black + rev: 25.9.0 + hooks: + - id: black + name: Black Formatter (Python) + - repo: https://github.com/pycqa/isort + rev: 6.0.1 + hooks: + - id: isort + name: Isort (Python) + args: ["--profile", "black", "--filter-files"] - repo: https://github.com/DavidAnson/markdownlint-cli2 - rev: v0.17.2 + rev: v0.18.1 hooks: - id: markdownlint-cli2 + name: MarkdownLint (Documentation) files: ^docs/.*|^README\.md$ types: - markdown - args: ["--fix", "--config", "docs/.markdownlint.yaml", "#**/node_modules"] + args: ["--fix", "--config", "docs/.markdownlint.yaml"] diff --git a/.prettierignore b/.prettierignore index 9d4f41bcd4..e45245d24d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,18 +1,12 @@ -**/node_modules/ **/pnpm-lock.yaml -docs/**/*.md MaaDeps/ 3rdparty/ src/maa-cli src/MaaMacGui -# website/ -# docs/ - resource/Arknights-Tile-Pos/ tools/OptimizeTemplates/optimize_templates.json CITATION.cff CHANGELOG.md -## FUCK FUCK \ No newline at end of file diff --git a/README.md b/README.md index 37430418d1..25011122f6 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,24 @@ MAA 以中文(简体)为第一语言,翻译词条均以中文(简体) [GitHub Pull Request 流程简述](https://docs.maa.plus/zh-cn/develop/development.html#github-pull-request-流程简述) +#### 想参与开发,但面对庞大的项目仓库望而却步? + +请使用 GitHub Codespaces 在线开发环境,尽情尝试! + +我们预置了多种不同的开发环境以供选择: + +- 空白环境,裸 Linux 容器(默认) + + [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights?devcontainer_path=.devcontainer%2Fdevcontainer.json) + +- 轻量环境,适合文档站前端开发 + + [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights?devcontainer_path=.devcontainer%2F0%2Fdevcontainer.json) + +- 全量环境,适合 MAA Core 相关开发 + + [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights?devcontainer_path=.devcontainer%2F1%2Fdevcontainer.json) + #### Issue bot 请参阅 [Issue Bot 使用方法](https://docs.maa.plus/zh-cn/develop/issue-bot-usage.html) diff --git a/docs/.prettierignore b/docs/.prettierignore index 3a1c1fa551..869a709766 100644 --- a/docs/.prettierignore +++ b/docs/.prettierignore @@ -1,2 +1 @@ **/pnpm-lock.yaml -**/*.md diff --git a/docs/.prettierrc.js b/docs/.prettierrc.js index 8a4ddba7f4..01be06da69 100644 --- a/docs/.prettierrc.js +++ b/docs/.prettierrc.js @@ -36,5 +36,11 @@ module.exports = { tabWidth: 4, }, }, + { + files: ['**/*.md'], + options: { + embeddedLanguageFormatting: 'off', + }, + }, ], } diff --git a/docs/KeepDrinking.md b/docs/KeepDrinking.md index 938894a8d6..3885fddc23 100644 --- a/docs/KeepDrinking.md +++ b/docs/KeepDrinking.md @@ -12,63 +12,59 @@ prev: false next: false --- - - !: .7:~!. - :. :?55 ?5~::~J?: - :P5YY?7~: .!JYYJG. 7P! .7Y!. - ^5JJJY55PPG5!. .?JYYJYG. ~P?. ~YJ: :PY~. - ^5YYYYYYY5PPPPYJ??7!!~^!?YYYYY5 :5Y. :J5!. :G^ - ~PY5555555PPPGGPPPPPPPPJ5YJYPP???5?57::.. !5J: Y&##P: - ^YPP5JJY5555PPGG55PP555PGPPPGGPPP555555555YYYJJ?77!~^::...~5P^:. P####7 - !GPPJ?JYYYYY5P5PPG57:...:!5GG?~!?JJY55PPPPPPPPPPP555555555YJYPYY57!~^::... .#####! - .?PY?YYYYYYY5PP5G?..:!??JYYPYY7. .....:^~!?JJYY5PPPPPPPP555555555555YYYJJ?77!!B####P - .5Y5YYYYYY555PGY.!?JYJJYJ5P:.?5^...:.::^~^^:::... ....::::~!!7?J5P55PPPPPPPP5P55PPGG###P - .:~?P5555PPPPGY:J77YYJY55Y: ..Y5?Y5PPGGBBBBGGGGP555J!^. ^~...^!77YY5G5::~:.:!5#G - ^5555PPPG5?.~5JYYYYY7: :~?5PPG5BBBBB########BBB####BGY7~~^:..:: .:^!~^~?Y7~. ~J7Y - P55PPPGY~...?5?~^:...:75PPGP5PG#####BGBBBBBBBBBB######BGGP5YJ???7!7JY?!!?YYYJYJ^^GJ.. - .!?P5YPB^ ....... :!J5PGB#######BBGY7~!!7?PYJJ7!5GB#######BBGPYYYYYJJYYYYY55GB##5^... - 75YYPG... .::::JPGB####BGPP55J5?^~~~~~~~~~~!!!?PGGBBBB#####GGBBBBBB##########&G^^~ - Y5YYGY... ..:^7PBB#####GPJ!~~~^~?!~~~~~~~~~~~~!!J7!7?JPG###&###############&&&~ - .PYY5B!... ..^YBBBB####GPJ~~~~~~~?J!~~~^^~~^^~~^^~!!::^75GB####&&&&&&&&&&&&&&##BG5 - ^PYY5G:... .^^PB#B###GP5JJ7~~~~~~~!7?~~~^..^:^~~~!~~~!~^~~5JJ555G##&&&&&&&#BBBGGPB! - ?5YYPP......:Y######G?!~!!~~~~~~~~~~!7^^^^:^~~~~~~!7~~!~^~~~~~!7?YGB###P77!:JGGGGB: - 5YYYGJ..... 7#B####GP!^~!~~~~~~^::!~~!~^^~~~~!~~~~~!J!~7!^~~~~~~!?Y5GPPPP5!^PGGGGP - .7 .PYY5B^..:::^GBB####PP!^7!^^~~~^^:^7~~~!^~~~~~~7~!~~~?5J?J7:~~~~~~~!?YY5YY55PPPGGGP~^: - ^5 ~PYYPG...:.!PP#####G5J!:?!^^~~~~~~~!~~~~^~~~~~!J7!??!!J!!JY~^~~~~~~~7?Y5YY55PPGGGGGB#P - ^G J5YYGY ..:!5YB####G5!^~~?!~~~!~~~~~~~~~~~~~~~!!77..~7^7~ .:7^~~~~!!~JGPPGGGBGB#####GY^ - ^&! 5YY5B! ^J5YGB###B5!^~~~?7~~~!7~~^??!~~~!~~~~~~!! :77!.::~!^~~~7!~!Y#########BBP. - ^&#~ :PYY5B:.!YYJG#####GG!~~~~7?~~~?J~7?P57~~~!7~~~!~7:..:~5PGBJ~^!^~~!J~~!7P##B###BGGG7 - ^&##Y^. ?P5PGGJYYYYPB#####BG!~~~~~J!~!55?7?!~J?!!77!777?::JPBBGP5J~ .!~~7J!~~!7YGG5BBGGGGB: - ^&###BG555YYYY5GBBB#B#####GGJ~~~~^7775?J~!!. .~??J?7??J7..!:7?7YY~7.^!~?J!~~!!7JP55PBGGGGG - ^&######BBBBB##########&#B5?!~~~~^~55~.7!~ .:~!7Y?J?!!~. :!~^~~.:^.??!!!7??YP5PPBGGGGY - ^&###################&##PY7~~!~~~~:?~ ^7:.^?5GBG7?!:. ... .:.:J????JY?5P57^:^75B! - .G&&&############&&&###GYJ?~~7~~~~~:!:.!YBBBGP5J^ :?JJJJJYGPG!. .. .5: - !G#&&&&&&&&&&&&#B5?GGGY5?~~~~~~~~~^755^~Y??57~!. :!J55YYY55GGPY .. !. - .~YBBBB#GYJ?77~7BBP55P7~7!~!77~~~~~~~^^^!~^~! .. ^?PGGGGGGG#BP7 !. - ^5YY5G^ ..!GP55555?YP5!~~!77!!7?J~. .^:. .. .^5#57GPBBBBBBP. ....:Y~ - J5YYPP:...:7GP55555GP5G#P!~~~~!!!7?!:^:...:^: .^J?5GP:.YPY7JJGB#Y .:~YGB. - 5YYYGJ:::^YGGY:?P5G#BB##B57!77777777???JJJYY: ..:~!!YP7YYP^ ??7~7?5BBBJ~!5GG5 - :PYY5B!:^JGGPGBJ5G#####PJGPPJ5Y????JJJJJYY5PY?YYY??JJJ?7~!~JBG: !??~!?YBBB#BGGGB7 - !5YYPG5GGGGB###?B###BB?!JG555PPYJ?77JYPP5GP57!J5G5YGGPY?!:~BP~^. .7J?~~?JBBB#5Y5GB: - Y5YY5Y5P5555^!PJPJ^?GGJYGPPGG!. .!Y55Y5Y: ..:~7J555JPPY!P~.~YJ?~~7JG#BBYYYPG - ^7?JJYYYY5557:.^^:7PPY55YY5P7 :. !PPPBP^... .J!5B5BB57JYP7?~~!J5B#GYYYGY - ...^J!~^.^JG55PPPPPGJ... . ~BP55PYJJJ?7~~^?5PGBBBGGPGGJ!^^~JYBBPYY5B! - ^^^:.:::?. ...:^~~~~^^::~!.:PGGPPPP5555555555555555PPPGP??7?YYBB5YY5B. - ...::^~!7?JYY5PPPPPPPP55555YYY555555555YYPP - ...:^~!7??JY555PPPPP55555BJ - ...:^^~!7?Y^ - - - - . . . . . - 7^.::?7:^: :7?:...P:. :~~~7P~~~^. :Y ^~~G!~~. :J?:^.?^^5 !! Y^ :Y.. ~~~^~Y!^~~: :P. :^^^JY .7~!.!~::5. - .:. ~^ 7? :YJ.77.P:~? Y~~7P~~J: ~7J^~!!P7!!.::JY?J:Y ?^ ^G..5~:P^!J .YJ Y7^Y Y^ :? 5 Y. P - Y: :JY? .GY^?!.P.~? :!!~?P~~?7 .^? !?!!!7? .7YJ~~ Y ^7.~Y.!7!!!~7: :7!~Y.!!^ 5 ~7^^!G^^::? 5 7~^~?J - Y^ ^~^.~! 7?!.::.P::: ~!!~?P!!J5. .J JJ!!~7P .57:^P Y: Y^ J.5 !7 PY 7~ :5 ^^ .YP: P :5~5:^^^^.P - !!~7!^:::!~ ~! Y .~?7 .. .? ?^ .~!J ?7^~5 J::. J.7::^7^~! :5 .!: : :~J ^^!? - . - - - + !: .7:~!. + :. :?55 ?5~::~J?: + :P5YY?7~: .!JYYJG. 7P! .7Y!. + ^5JJJY55PPG5!. .?JYYJYG. ~P?. ~YJ: :PY~. + ^5YYYYYYY5PPPPYJ??7!!~^!?YYYYY5 :5Y. :J5!. :G^ + ~PY5555555PPPGGPPPPPPPPJ5YJYPP???5?57::.. !5J: Y&##P: + ^YPP5JJY5555PPGG55PP555PGPPPGGPPP555555555YYYJJ?77!~^::...~5P^:. P####7 + !GPPJ?JYYYYY5P5PPG57:...:!5GG?~!?JJY55PPPPPPPPPPP555555555YJYPYY57!~^::... .#####! + .?PY?YYYYYYY5PP5G?..:!??JYYPYY7. .....:^~!?JJYY5PPPPPPPP555555555555YYYJJ?77!!B####P + .5Y5YYYYYY555PGY.!?JYJJYJ5P:.?5^...:.::^~^^:::... ....::::~!!7?J5P55PPPPPPPP5P55PPGG###P + .:~?P5555PPPPGY:J77YYJY55Y: ..Y5?Y5PPGGBBBBGGGGP555J!^. ^~...^!77YY5G5::~:.:!5#G + ^5555PPPG5?.~5JYYYYY7: :~?5PPG5BBBBB########BBB####BGY7~~^:..:: .:^!~^~?Y7~. ~J7Y + P55PPPGY~...?5?~^:...:75PPGP5PG#####BGBBBBBBBBBB######BGGP5YJ???7!7JY?!!?YYYJYJ^^GJ.. + .!?P5YPB^ ....... :!J5PGB#######BBGY7~!!7?PYJJ7!5GB#######BBGPYYYYYJJYYYYY55GB##5^... + 75YYPG... .::::JPGB####BGPP55J5?^~~~~~~~~~~!!!?PGGBBBB#####GGBBBBBB##########&G^^~ + Y5YYGY... ..:^7PBB#####GPJ!~~~^~?!~~~~~~~~~~~~!!J7!7?JPG###&###############&&&~ + .PYY5B!... ..^YBBBB####GPJ~~~~~~~?J!~~~^^~~^^~~^^~!!::^75GB####&&&&&&&&&&&&&&##BG5 + ^PYY5G:... .^^PB#B###GP5JJ7~~~~~~~!7?~~~^..^:^~~~!~~~!~^~~5JJ555G##&&&&&&&#BBBGGPB! + ?5YYPP......:Y######G?!~!!~~~~~~~~~~!7^^^^:^~~~~~~!7~~!~^~~~~~!7?YGB###P77!:JGGGGB: + 5YYYGJ..... 7#B####GP!^~!~~~~~~^::!~~!~^^~~~~!~~~~~!J!~7!^~~~~~~!?Y5GPPPP5!^PGGGGP + .7 .PYY5B^..:::^GBB####PP!^7!^^~~~^^:^7~~~!^~~~~~~7~!~~~?5J?J7:~~~~~~~!?YY5YY55PPPGGGP~^: + ^5 ~PYYPG...:.!PP#####G5J!:?!^^~~~~~~~!~~~~^~~~~~!J7!??!!J!!JY~^~~~~~~~7?Y5YY55PPGGGGGB#P + ^G J5YYGY ..:!5YB####G5!^~~?!~~~!~~~~~~~~~~~~~~~!!77..~7^7~ .:7^~~~~!!~JGPPGGGBGB#####GY^ + ^&! 5YY5B! ^J5YGB###B5!^~~~?7~~~!7~~^??!~~~!~~~~~~!! :77!.::~!^~~~7!~!Y#########BBP. + ^&#~ :PYY5B:.!YYJG#####GG!~~~~7?~~~?J~7?P57~~~!7~~~!~7:..:~5PGBJ~^!^~~!J~~!7P##B###BGGG7 + ^&##Y^. ?P5PGGJYYYYPB#####BG!~~~~~J!~!55?7?!~J?!!77!777?::JPBBGP5J~ .!~~7J!~~!7YGG5BBGGGGB: + ^&###BG555YYYY5GBBB#B#####GGJ~~~~^7775?J~!!. .~??J?7??J7..!:7?7YY~7.^!~?J!~~!!7JP55PBGGGGG + ^&######BBBBB##########&#B5?!~~~~^~55~.7!~ .:~!7Y?J?!!~. :!~^~~.:^.??!!!7??YP5PPBGGGGY + ^&###################&##PY7~~!~~~~:?~ ^7:.^?5GBG7?!:. ... .:.:J????JY?5P57^:^75B! + .G&&&############&&&###GYJ?~~7~~~~~:!:.!YBBBGP5J^ :?JJJJJYGPG!. .. .5: + !G#&&&&&&&&&&&&#B5?GGGY5?~~~~~~~~~^755^~Y??57~!. :!J55YYY55GGPY .. !. + .~YBBBB#GYJ?77~7BBP55P7~7!~!77~~~~~~~^^^!~^~! .. ^?PGGGGGGG#BP7 !. + ^5YY5G^ ..!GP55555?YP5!~~!77!!7?J~. .^:. .. .^5#57GPBBBBBBP. ....:Y~ + J5YYPP:...:7GP55555GP5G#P!~~~~!!!7?!:^:...:^: .^J?5GP:.YPY7JJGB#Y .:~YGB. + 5YYYGJ:::^YGGY:?P5G#BB##B57!77777777???JJJYY: ..:~!!YP7YYP^ ??7~7?5BBBJ~!5GG5 + :PYY5B!:^JGGPGBJ5G#####PJGPPJ5Y????JJJJJYY5PY?YYY??JJJ?7~!~JBG: !??~!?YBBB#BGGGB7 + !5YYPG5GGGGB###?B###BB?!JG555PPYJ?77JYPP5GP57!J5G5YGGPY?!:~BP~^. .7J?~~?JBBB#5Y5GB: + Y5YY5Y5P5555^!PJPJ^?GGJYGPPGG!. .!Y55Y5Y: ..:~7J555JPPY!P~.~YJ?~~7JG#BBYYYPG + ^7?JJYYYY5557:.^^:7PPY55YY5P7 :. !PPPBP^... .J!5B5BB57JYP7?~~!J5B#GYYYGY + ...^J!~^.^JG55PPPPPGJ... . ~BP55PYJJJ?7~~^?5PGBBBGGPGGJ!^^~JYBBPYY5B! + ^^^:.:::?. ...:^~~~~^^::~!.:PGGPPPP5555555555555555PPPGP??7?YYBB5YY5B. + ...::^~!7?JYY5PPPPPPPP55555YYY555555555YYPP + ...:^~!7??JY555PPPPP55555BJ + ...:^^~!7?Y^ + + + + . . . . . + 7^.::?7:^: :7?:...P:. :~~~7P~~~^. :Y ^~~G!~~. :J?:^.?^^5 !! Y^ :Y.. ~~~^~Y!^~~: :P. :^^^JY .7~!.!~::5. + .:. ~^ 7? :YJ.77.P:~? Y~~7P~~J: ~7J^~!!P7!!.::JY?J:Y ?^ ^G..5~:P^!J .YJ Y7^Y Y^ :? 5 Y. P + Y: :JY? .GY^?!.P.~? :!!~?P~~?7 .^? !?!!!7? .7YJ~~ Y ^7.~Y.!7!!!~7: :7!~Y.!!^ 5 ~7^^!G^^::? 5 7~^~?J + Y^ ^~^.~! 7?!.::.P::: ~!!~?P!!J5. .J JJ!!~7P .57:^P Y: Y^ J.5 !7 PY 7~ :5 ^^ .YP: P :5~5:^^^^.P + !!~7!^:::!~ ~! Y .~?7 .. .? ?^ .~!J ?7^~5 J::. J.7::^7^~! :5 .!: : :~J ^^!? + . diff --git a/docs/en-us/develop/ci-tutorial.md b/docs/en-us/develop/ci-tutorial.md index 16c15e5433..d1b72cb59e 100644 --- a/docs/en-us/develop/ci-tutorial.md +++ b/docs/en-us/develop/ci-tutorial.md @@ -15,15 +15,15 @@ You can quickly navigate to the section you want to see by searching for CI file 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) +- [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. @@ -51,10 +51,10 @@ This workflow runs automatically on any new commit and PR. When triggered by a r 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 +- `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. @@ -82,9 +82,9 @@ The release process for these two channels is relatively more complex. We'll exp 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 +- `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 @@ -119,8 +119,8 @@ This workflow checks whether commit messages in PRs conform to [Conventional Com 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 +- `mirrorchyan.yml` Sync update packages to MirrorChyan +- `mirrorchyan_release_note.yml` Generate MirrorChyan Release Notes ### Others diff --git a/docs/en-us/develop/development.md b/docs/en-us/develop/development.md index ec7a343b86..bd6fc75bf2 100644 --- a/docs/en-us/develop/development.md +++ b/docs/en-us/develop/development.md @@ -21,42 +21,40 @@ Welcome to the [Web-based PR Tutorial](./pr-tutorial.md) that anyone can underst 2. Visit the [MAA main repository](https://github.com/MaaAssistantArknights/MaaAssistantArknights), click `Fork`, then `Create fork`. 3. Clone the dev branch of your repository with submodules: - ```bash - git clone --recurse-submodules -b dev - ``` + ```bash + git clone --recurse-submodules -b dev + ``` - ::: warning - If using Git GUI clients like Visual Studio without `--recurse-submodules` support, run `git submodule update --init` after cloning to initialize submodules. - ::: + ::: warning + If using Git GUI clients like Visual Studio without `--recurse-submodules` support, run `git submodule update --init` after cloning to initialize submodules. + ::: 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)_ - ```cmd - python tools/maadeps-download.py - ``` + ```cmd + python tools/maadeps-download.py + ``` 5. Configure development environment - - - Download and install `Visual Studio 2022 Community`, selecting `Desktop development with C++` and `.NET Desktop Development` during installation. + - Download and install `Visual Studio 2022 Community`, selecting `Desktop development with C++` and `.NET Desktop Development` during installation. 6. Double-click `MAA.sln` to open the project in Visual Studio. 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) + - 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) 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`: - ```bash - git branch your_own_branch - git checkout your_own_branch - ``` + ```bash + git branch your_own_branch + git checkout your_own_branch + ``` - This keeps your changes isolated from upstream `dev` updates. + This keeps your changes isolated from upstream `dev` updates. 10. After development, push your local branch (e.g. `dev`) to your remote repository: @@ -66,30 +64,29 @@ Welcome to the [Web-based PR Tutorial](./pr-tutorial.md) that anyone can underst 11. Submit a Pull Request at the [MAA main repository](https://github.com/MaaAssistantArknights/MaaAssistantArknights). Ensure your changes are based on the `dev` branch, not `master`. 12. To sync upstream changes: - 1. Add upstream repository: - ```bash - git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git - ``` + ```bash + git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git + ``` 2. Fetch updates: - ```bash - git fetch upstream - ``` + ```bash + git fetch upstream + ``` 3. Rebase (recommended) or merge: - ```bash - git rebase upstream/dev # rebase - ``` + ```bash + git rebase upstream/dev # rebase + ``` - or + or - ```bash - git merge # merge - ``` + ```bash + git merge # merge + ``` 4. Repeat steps 7, 8, 9, 10. @@ -105,11 +102,11 @@ Please ensure that it has been formatted before submission, or [enable Pre-commi The currently enabled formatting tools are as follows: -| File Type | Format Tool | -| --- | --- | -| C++ | [clang-format](https://clang.llvm.org/docs/ClangFormat.html) | -| Json/Yaml | [Prettier](https://prettier.io/) | -| Markdown | [markdownlint](https://github.com/DavidAnson/markdownlint-cli2) | +| File Type | Format Tool | +| --------- | --------------------------------------------------------------- | +| C++ | [clang-format](https://clang.llvm.org/docs/ClangFormat.html) | +| Json/Yaml | [Prettier](https://prettier.io/) | +| Markdown | [markdownlint](https://github.com/DavidAnson/markdownlint-cli2) | ### Use Pre-commit Hooks to Automatically Format Code @@ -117,10 +114,10 @@ The currently enabled formatting tools are as follows: 2. Execute the following command in the root directory of the project: - ```bash - pip install pre-commit - pre-commit install - ``` + ```bash + pip install pre-commit + pre-commit install + ``` If pre-commit still cannot be used after pip install, please check if the pip installation path has been added to the PATH. @@ -130,9 +127,9 @@ The formatting tool will automatically run every time you submit to ensure that 1. Install clang-format version 20.1.0 or higher. - ```bash - python -m pip install clang-format - ``` + ```bash + python -m pip install clang-format + ``` 2. Use tools like 'Everything' to locate the installation location of clang-format.exe. As a reference, if you are using Anaconda, clang-format.exe will be installed in YourAnacondaPath/Scripts/clang-format.exe. 3. In Visual Studio, search for 'clang-format' in Tools-Options. @@ -150,6 +147,4 @@ You can also format with `tools\ClangFormatter\clang-formatter.py` directly, by Create GitHub codespace with pre-configured C++ dev environments: -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights) - -Then follow the instructions in vscode or [Linux tutorial](./linux-tutorial.md) to configure GCC 12 and the CMake project. +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights?devcontainer_path=.devcontainer%2F1%2Fdevcontainer.json) diff --git a/docs/en-us/develop/issue-bot-usage.md b/docs/en-us/develop/issue-bot-usage.md index 51f2cad508..d4e1f5ba2a 100644 --- a/docs/en-us/develop/issue-bot-usage.md +++ b/docs/en-us/develop/issue-bot-usage.md @@ -16,8 +16,8 @@ Your pull request will be marked as `ambiguous` when you are not committing with ### Auto Notification - Adds labels to issues and pull requests, e.g., `module`, `Client`, `ambiguous`, `translation required`, etc. - Issue Bot will add categories based on keywords. - Please refer to the [configuration file](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/.github/issue-checker.yml) for the keywords. + Issue Bot will add categories based on keywords. + Please refer to the [configuration file](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/.github/issue-checker.yml) for the keywords. - Adds the `MAA Team` label to issues and pull requests for MAA public team members. #### Issues and Their Comments diff --git a/docs/en-us/develop/linux-tutorial.md b/docs/en-us/develop/linux-tutorial.md index 970975ee91..ff4a6735cc 100644 --- a/docs/en-us/develop/linux-tutorial.md +++ b/docs/en-us/develop/linux-tutorial.md @@ -18,63 +18,60 @@ Mac can use the `tools/build_macos_universal.zsh` script for compilation. It's r ## Compilation Process 1. Download compilation dependencies + - Ubuntu/Debian - - Ubuntu/Debian + ```bash + sudo apt install cmake + ``` - ```bash - sudo apt install cmake - ``` + - Arch Linux - - Arch Linux - - ```bash - sudo pacman -S --needed cmake - ``` + ```bash + sudo pacman -S --needed cmake + ``` 2. Build third-party libraries - You can choose to download pre-built dependency libraries or compile from scratch + You can choose to download pre-built dependency libraries or compile from scratch + - Download pre-built third-party libraries (recommended) - - Download pre-built third-party 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. - > **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. + ```bash + python tools/maadeps-download.py + ``` - ```bash - python tools/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 + - Build third-party libraries from scratch (will take considerable time) - 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 - - - Build third-party libraries from scratch (will take considerable time) - - ```bash - git clone https://github.com/MaaAssistantArknights/MaaDeps - cd MaaDeps - # If the system is too old to use our prebuilt llvm 20, please consider using local build enviroment instead of cross compiling. - # The toolchain config under MaaDeps/cmake needs to be modified. - python linux-toolchain-download.py - python build.py - ``` + ```bash + git clone https://github.com/MaaAssistantArknights/MaaDeps + cd MaaDeps + # If the system is too old to use our prebuilt llvm 20, please consider using local build enviroment instead of cross compiling. + # The toolchain config under MaaDeps/cmake needs to be modified. + python linux-toolchain-download.py + python build.py + ``` 3. Compile MAA - ```bash - cmake -B build \ - -DINSTALL_RESOURCE=ON \ - -DINSTALL_PYTHON=ON \ - -DCMAKE_TOOLCHAIN_FILE=MaaDeps/cmake/maa-x64-linux-toolchain.cmake - cmake --build build - ``` + ```bash + cmake -B build \ + -DINSTALL_RESOURCE=ON \ + -DINSTALL_PYTHON=ON \ + -DCMAKE_TOOLCHAIN_FILE=MaaDeps/cmake/maa-x64-linux-toolchain.cmake + 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` + 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` + > Now it shall be able to run without specifying `LD_LIBRARY_PATH` - ```bash - cmake --install build --prefix - ``` + ```bash + cmake --install build --prefix + ``` ## Integration Documentation diff --git a/docs/en-us/develop/pr-tutorial.md b/docs/en-us/develop/pr-tutorial.md index ec67cb645e..b312d62663 100644 --- a/docs/en-us/develop/pr-tutorial.md +++ b/docs/en-us/develop/pr-tutorial.md @@ -72,21 +72,21 @@ Conflicts are somewhat troublesome to resolve. This section only explains the co 1. First, enter MAA's main repository and click the Fork button in the upper right corner to fork a copy of the code - + 2. Then directly click "Create Fork" - + 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" @@ -98,13 +98,13 @@ Conflicts are somewhat troublesome to resolve. This section only explains the co 7. After editing, click the button in the upper right corner to open the commit page and write what you changed - 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. + 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. 8. Have a second file to modify? Discovered an error after finishing? No problem! Just repeat steps 4-7! 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. + 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. 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. diff --git a/docs/en-us/develop/vsc-ext-tutorial.md b/docs/en-us/develop/vsc-ext-tutorial.md index f65d3aab57..a0bdeac5ea 100644 --- a/docs/en-us/develop/vsc-ext-tutorial.md +++ b/docs/en-us/develop/vsc-ext-tutorial.md @@ -5,8 +5,8 @@ icon: iconoir:code-brackets # Dedicated VSCode Extension Tutorial -* [Extension Store](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) -* [Repository](https://github.com/neko-para/maa-support-extension) +- [Extension Store](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) +- [Repository](https://github.com/neko-para/maa-support-extension) ## Installation @@ -60,10 +60,10 @@ When enabling the `Maa` compatible mode, the extension will be able to recursive The extension supports scheduled scanning and diagnosing all tasks. -* Check if contains task defs with same names. -* Check if contains unknown task refs. -* Check if contains unknown image refs. -* Check if contains duplicated task refs in a single task. +- Check if contains task defs with same names. +- Check if contains unknown task refs. +- Check if contains unknown image refs. +- Check if contains duplicated task refs in a single task. #### Multiple paths resource support @@ -83,11 +83,11 @@ Searching and launching `Maa: open crop tool` inside VSCode command panel can op > Use `Ctrl+Shift+P` (`Command+Shift+P` on MacOS) to open command panel -* After selecting and connecting to the controller, use `Screencap` button to obtain screenshots -* Use `Upload` button to manually upload images. -* Hold `Ctrl` key and select cropping area -* Use wheels to zoom -* After finishing cropping, use `Download` button to save the cropping result to the folder of the topest layer of the activated resource +- After selecting and connecting to the controller, use `Screencap` button to obtain screenshots +- Use `Upload` button to manually upload images. +- Hold `Ctrl` key and select cropping area +- Use wheels to zoom +- After finishing cropping, use `Download` button to save the cropping result to the folder of the topest layer of the activated resource ### Bottom status bar diff --git a/docs/en-us/manual/connection.md b/docs/en-us/manual/connection.md index bc01eb1c94..8aafe5370c 100644 --- a/docs/en-us/manual/connection.md +++ b/docs/en-us/manual/connection.md @@ -63,7 +63,6 @@ For other emulators, refer to [Zhao Qingqing's blog](https://www.cnblogs.com/zha ::: details Alternative methods - Method 1: Check emulator ports using ADB commands - 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: @@ -86,7 +85,6 @@ For other emulators, refer to [Zhao Qingqing's blog](https://www.cnblogs.com/zha Use `127.0.0.1:` or `emulator-` as your connection address. - 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`. @@ -131,7 +129,6 @@ MAA now attempts to read the `bluestacks.conf` storage location from the registr ::: 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` diff --git a/docs/en-us/manual/device/android.md b/docs/en-us/manual/device/android.md index 5bed3bd672..7ebbfd6b51 100644 --- a/docs/en-us/manual/device/android.md +++ b/docs/en-us/manual/device/android.md @@ -17,6 +17,7 @@ This method involves ADB command-line usage, has lower stability, and still requ 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. + ::: ::: tip @@ -36,7 +37,6 @@ Typical `16:9` resolutions include `3840x2160` (4K), `2560x1440` (2K), `1920x108 ``` - When executed successfully, it will show connected USB debugging devices. - - Example of a successful connection: ```bash @@ -118,7 +118,6 @@ Strongly recommended to restore the default resolution **before** restarting you ``` 2. Rename the first file to `startup.bat` and the second 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." 3. In MAA's `Settings` - `Connection Settings`, set `Start Script` to `startup.bat` and `End Script` to `finish.bat`. @@ -149,7 +148,6 @@ Wired connections don't need IP addresses or ports - just the device serial numb ``` 2. Find your device's 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. @@ -165,7 +163,6 @@ Wired connections don't need IP addresses or ports - just the device serial numb 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. 2. Complete the pairing: - 1. In the command prompt, type `adb pair ` and press Enter. 2. Enter the six-digit pairing code from the device popup and press Enter. 3. When you see `Successfully paired to `, the device popup will close automatically, and your computer's name will appear in the paired devices list. diff --git a/docs/en-us/manual/device/linux.md b/docs/en-us/manual/device/linux.md index 002da91cf1..67d0a1f14c 100644 --- a/docs/en-us/manual/device/linux.md +++ b/docs/en-us/manual/device/linux.md @@ -59,7 +59,6 @@ Place the `MaaDesktopIntegration.so` generated by MAA Wine Bridge in the same di #### 1. Installing MAA Dynamic Library 1. Download and extract the Linux dynamic library from the [MAA website](https://maa.plus/), or install from a software repository: - - AUR: [maa-assistant-arknights](https://aur.archlinux.org/packages/maa-assistant-arknights), follow the post-installation instructions - Nixpkgs: [maa-assistant-arknights](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-assistant-arknights/package.nix) @@ -75,7 +74,6 @@ You can refer to the [Linux Compilation Tutorial](../../develop/linux-tutorial.m 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) 2. ADB Tool Configuration - - 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: ```python @@ -85,7 +83,6 @@ You can refer to the [Linux Compilation Tutorial](../../develop/linux-tutorial.m - 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. 3. Getting the Emulator's ADB Address - - Use the ADB tool directly: `$ adb_path devices`, for example: ```shell diff --git a/docs/en-us/manual/faq.md b/docs/en-us/manual/faq.md index 75c309d22b..e635663d9c 100644 --- a/docs/en-us/manual/faq.md +++ b/docs/en-us/manual/faq.md @@ -22,6 +22,7 @@ Or manually download and install these **two** runtime libraries to solve - [Visual C++ Redistributable](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 diff --git a/docs/en-us/manual/introduction/combat.md b/docs/en-us/manual/introduction/combat.md index 004bba18bd..561a47d0df 100644 --- a/docs/en-us/manual/introduction/combat.md +++ b/docs/en-us/manual/introduction/combat.md @@ -8,7 +8,6 @@ icon: hugeicons:brain-02 ## 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. - - `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"). @@ -19,19 +18,19 @@ icon: hugeicons:brain-02 ::: details Examples -| 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_ | +| 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_ | ::: @@ -46,7 +45,6 @@ icon: hugeicons:brain-02 - 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 diff --git a/docs/en-us/manual/newbie.md b/docs/en-us/manual/newbie.md index 1d9e6cd0ea..98c919c8bf 100644 --- a/docs/en-us/manual/newbie.md +++ b/docs/en-us/manual/newbie.md @@ -11,31 +11,31 @@ Quick start guide! 1. Confirm system version - MAA on Windows only supports Windows 10 and 11. For older Windows versions, please refer to the system issues section in [FAQ](./faq.md#system-issues). + MAA on Windows only supports Windows 10 and 11. For older Windows versions, please refer to the system issues section in [FAQ](./faq.md#system-issues). - Non-Windows users, please refer to [Emulator and Device Support](./device/). + Non-Windows users, please refer to [Emulator and Device Support](./device/). 2. Download the correct version - The [MAA official website](https://maa.plus/) will automatically select the correct architecture for most users reading this article, which should be Windows x64. + The [MAA official website](https://maa.plus/) will automatically select the correct architecture for most users reading this article, which should be Windows x64. 3. Extract correctly - Ensure the extraction is complete, and make sure to extract MAA to a separate folder. Do not extract MAA to paths requiring UAC permissions such as `C:\` or `C:\Program Files\`. + Ensure the extraction is complete, and make sure to extract MAA to a separate folder. Do not extract MAA to paths requiring UAC permissions such as `C:\` or `C:\Program Files\`. 4. Install runtime libraries - MAA requires VCRedist x64 and .NET 8. Please run `DependencySetup_依赖库安装.bat` in the MAA directory to install them. + MAA requires VCRedist x64 and .NET 8. Please run `DependencySetup_依赖库安装.bat` in the MAA directory to install them. - For more information, please refer to the pinned section in [FAQ](./faq.md). + For more information, please refer to the pinned section in [FAQ](./faq.md). 5. Confirm emulator support - Check [Emulator and Device Support](./device/) to verify the compatibility of your emulator. + Check [Emulator and Device Support](./device/) to verify the compatibility of your emulator. 6. Set the correct emulator resolution - Emulator resolution should be landscape `1280x720` or `1920x1080`; for YostarEN players, it must be `1920x1080`. + Emulator resolution should be landscape `1280x720` or `1920x1080`; for YostarEN players, it must be `1920x1080`. ## Initial Configuration diff --git a/docs/en-us/protocol/callback-schema.md b/docs/en-us/protocol/callback-schema.md index 1dc3e61b54..addd839316 100644 --- a/docs/en-us/protocol/callback-schema.md +++ b/docs/en-us/protocol/callback-schema.md @@ -202,7 +202,7 @@ Todo #### Common `subtask` Field Values -- `ProcessTask` +- `ProcessTask` ```json // Corresponding details field example diff --git a/docs/en-us/protocol/integrated-strategy-schema.md b/docs/en-us/protocol/integrated-strategy-schema.md index 40d2b40b2e..75b0360072 100644 --- a/docs/en-us/protocol/integrated-strategy-schema.md +++ b/docs/en-us/protocol/integrated-strategy-schema.md @@ -51,12 +51,12 @@ The tools in `tools/RoguelikeRecruitmentTool` and `tools/RoguelikeOperSearch` ca "team_complete_condition": [ // Conditions for squad completness ... ] -} +} ``` ### Operator classification -Split operators in different ***groups*** according to your understanding of the game (Group concept references [Copilot Schema](./copilot-schema.md)) +Split operators in different **_groups_** according to your understanding of the game (Group concept references [Copilot Schema](./copilot-schema.md)) ::: info @@ -67,6 +67,7 @@ Split operators in different ***groups*** according to your understanding of the 3. Please do not change the name of an existing group, as this may cause previous versions of the task to be unavailable when MAA is updated! 4. Please try not to add new groups, instead try to implement new operators added to the task into existing groups according to their usage + ::: ::: tip @@ -75,7 +76,7 @@ By default, only E1 Level 55 operators will be recruited ```json { - "theme": "Phantom", + "theme": "Phantom", "priority": [ // Groups, in order { "name": "棘刺", // Group name ("棘刺" = "Thorns") @@ -91,7 +92,7 @@ By default, only E1 Level 55 operators will be recruited } ] }, - "team_complete_condition": [ + "team_complete_condition": [ ... ] ] @@ -100,60 +101,60 @@ By default, only E1 Level 55 operators will be recruited 1. Introduction to existing groups - Taking Sami's I.S. as an example: operators are mainly divided into: + Taking Sami's I.S. as an example: operators are mainly divided into: - | Group | Considerations | Class | Operators | - | :--- | :--- | :--- | :--- | - | ***地面阻挡*** (Ground Blocking) | Field presence and clearing enemies | Defenders, Guards | Healing defenders, cornerstones, Blacknight, Mountain, M3, Ling and Scene's summons, Spot, Defender reserve operators | - | ***地面单切/处决者*** (Ground Single-Target/Executors) | Solo elite enemies | Executor specialists | SilverAsh, Yato the Elegy, Kirara R Yato, M3, Red | - | ***高台C*** (Ranged Core) | Sustained and decisive output | Snipers, Casters | Weathered, Logos, Ch'en the Holungday, Chongyue | - | ***高台输出*** (Ranged DPS) | Anti-air and sustained output | Snipers, Casters | Archetto, Exusiai, Kroos, Steward | - | ***速狙*** (Fast Snipers) | Physical damage, standard range | Snipers | Eyjafjalla, Exusiai, Yeye, Kroos | - | ***术师*** (Casters) | Arts damage, standard range | Single-target Casters | Eyjafjalla, Logos, Steward | - | ***辅助*** (Supporters) | Can hit 1 tile behind | Supporters | Suzuran, Lily of the Valley, Yeye, Orchid | - | ***狙击*** (Long-range Snipers) | Longer range high ground | Artilleryman, Spreadshooter | Weathered, Toddifons, Rosa | - | ***奶*** (Healers) | Healing ability | Medics, Supporters | Kal'tsit, Skadi the Corrupting Heart, Hibiscus, Ansel | - | ***单奶*** (Single-target Healers) | Attack range depth >= 4 | Medics | Kal'tsit, Reed the Flame Shadow, Ptilopsis, Perfumer, Hibiscus, Ansel | - | ***群奶*** (AoE Healers) | Attack range depth < 4, can heal behind | Medics, Supporters | Nightingale, Ptilopsis, Skadi the Corrupting Heart | - | ***回费*** (DP Recovery) | Cost recovery | Vanguards | Myrtle, Ines, Fang, Vanilla | - | ***地刺*** (Ground Traps) | No blocking, provides DPS or slowing in front of defenders | Ambushers | Gladiia, Ascalon, Manticore | - | ***地面远程*** (Ground Ranged) | Ground long-range, can output behind shields | Instructors, Lords | Horn, Pallas, Thorns, SilverAsh | - | ***领主*** (Lords) | Ground attack range depth > 4, can target air | Fortress, Lord | Thorns, SilverAsh, Chouyu | - | ***盾法*** (Shield Casters) | Short attack range, some tanking ability | Arts Fighter Casters | Lin, Carnelian | - | ***炮灰*** (Fodder) | Absorb attacks, redeploy | Specialists, summons | M3, Red, Myrtle, reserve operators | - | ***大龙*** (Big Dragon) | Tank in front of blockers, easy to combine | Summons | Ling's dragons, Jessica the Flame Purifier's shield | - | ***补给站*** (Supply Stations) | Accelerate main DPS operator skill rotation | Summons | Support Supply Station, Artificer operator summons | - | ***无人机*** (Drones) | Ignore height restrictions for healing summons | Summons | Skadi's Seaborn, Silence's Medical Drone | - | ***支援陷阱*** (Support Traps) | Deployable ground explosives | Summons | Support Mist Generator, Support Rumble-Rumble | - | ***障碍物*** (Obstacles) | Don't take deployment slots, attract aggro or block | Summons | Cage, obstacles | - | ***其他地面*** (Other Ground) | Ground operators not preferred for priority use | Push/pull, block-1 vanguards, swordmasters | Bagpipe, Croissant | - | ***高台预备/其他高台*** (High Ground Reserve/Other High Ground) | High ground operators not preferred for priority use | AoE casters, chain casters, tacticians | Orchid, reserve operators | + | Group | Considerations | Class | Operators | + | :-------------------------------------------------------------- | :--------------------------------------------------------- | :----------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | + | **_地面阻挡_** (Ground Blocking) | Field presence and clearing enemies | Defenders, Guards | Healing defenders, cornerstones, Blacknight, Mountain, M3, Ling and Scene's summons, Spot, Defender reserve operators | + | **_地面单切/处决者_** (Ground Single-Target/Executors) | Solo elite enemies | Executor specialists | SilverAsh, Yato the Elegy, Kirara R Yato, M3, Red | + | **_高台C_** (Ranged Core) | Sustained and decisive output | Snipers, Casters | Weathered, Logos, Ch'en the Holungday, Chongyue | + | **_高台输出_** (Ranged DPS) | Anti-air and sustained output | Snipers, Casters | Archetto, Exusiai, Kroos, Steward | + | **_速狙_** (Fast Snipers) | Physical damage, standard range | Snipers | Eyjafjalla, Exusiai, Yeye, Kroos | + | **_术师_** (Casters) | Arts damage, standard range | Single-target Casters | Eyjafjalla, Logos, Steward | + | **_辅助_** (Supporters) | Can hit 1 tile behind | Supporters | Suzuran, Lily of the Valley, Yeye, Orchid | + | **_狙击_** (Long-range Snipers) | Longer range high ground | Artilleryman, Spreadshooter | Weathered, Toddifons, Rosa | + | **_奶_** (Healers) | Healing ability | Medics, Supporters | Kal'tsit, Skadi the Corrupting Heart, Hibiscus, Ansel | + | **_单奶_** (Single-target Healers) | Attack range depth >= 4 | Medics | Kal'tsit, Reed the Flame Shadow, Ptilopsis, Perfumer, Hibiscus, Ansel | + | **_群奶_** (AoE Healers) | Attack range depth < 4, can heal behind | Medics, Supporters | Nightingale, Ptilopsis, Skadi the Corrupting Heart | + | **_回费_** (DP Recovery) | Cost recovery | Vanguards | Myrtle, Ines, Fang, Vanilla | + | **_地刺_** (Ground Traps) | No blocking, provides DPS or slowing in front of defenders | Ambushers | Gladiia, Ascalon, Manticore | + | **_地面远程_** (Ground Ranged) | Ground long-range, can output behind shields | Instructors, Lords | Horn, Pallas, Thorns, SilverAsh | + | **_领主_** (Lords) | Ground attack range depth > 4, can target air | Fortress, Lord | Thorns, SilverAsh, Chouyu | + | **_盾法_** (Shield Casters) | Short attack range, some tanking ability | Arts Fighter Casters | Lin, Carnelian | + | **_炮灰_** (Fodder) | Absorb attacks, redeploy | Specialists, summons | M3, Red, Myrtle, reserve operators | + | **_大龙_** (Big Dragon) | Tank in front of blockers, easy to combine | Summons | Ling's dragons, Jessica the Flame Purifier's shield | + | **_补给站_** (Supply Stations) | Accelerate main DPS operator skill rotation | Summons | Support Supply Station, Artificer operator summons | + | **_无人机_** (Drones) | Ignore height restrictions for healing summons | Summons | Skadi's Seaborn, Silence's Medical Drone | + | **_支援陷阱_** (Support Traps) | Deployable ground explosives | Summons | Support Mist Generator, Support Rumble-Rumble | + | **_障碍物_** (Obstacles) | Don't take deployment slots, attract aggro or block | Summons | Cage, obstacles | + | **_其他地面_** (Other Ground) | Ground operators not preferred for priority use | Push/pull, block-1 vanguards, swordmasters | Bagpipe, Croissant | + | **_高台预备/其他高台_** (High Ground Reserve/Other High Ground) | High ground operators not preferred for priority use | AoE casters, chain casters, tacticians | Orchid, reserve operators | - ::: tip - "Ground Blocking" mainly considers an operator's overall defensive capabilities (sometimes killing everything is also a form of defense), including "Ground Ranged" and "Lord" groups. + ::: tip + "Ground Blocking" mainly considers an operator's overall defensive capabilities (sometimes killing everything is also a form of defense), including "Ground Ranged" and "Lord" groups. - "Healers" mainly considers overall healing ability, including single-target and AoE healers. Consider attack range coverage when deciding whether to use single-target healers (healing 4 tiles) or AoE healers (healing behind). + "Healers" mainly considers overall healing ability, including single-target and AoE healers. Consider attack range coverage when deciding whether to use single-target healers (healing 4 tiles) or AoE healers (healing behind). - "Ranged DPS" only considers output ability, mainly a mixed ordering of sniper and caster professions. Consider damage type, attack range and other restrictions when using specific groups like fast snipers, casters, supporters, or shield casters. + "Ranged DPS" only considers output ability, mainly a mixed ordering of sniper and caster professions. Consider damage type, attack range and other restrictions when using specific groups like fast snipers, casters, supporters, or shield casters. - For trap-type summons, because there are many of them, don't put them in the support trap group. It works better to let MAA deploy them automatically. - ::: + For trap-type summons, because there are many of them, don't put them in the support trap group. It works better to let MAA deploy them automatically. + ::: 2. Groups requiring special handling - In addition to those general groups, sometimes we need more custom tweaks for some operators or types such as + In addition to those general groups, sometimes we need more custom tweaks for some operators or types such as - | Group | Operators | Features | - | :--- | :--- | :--- | - | 益达 (Weathered) | 维什戴尔 (Weathered) | High ground DPS, prioritizing deployment can reduce pressure | - | 棘刺 (Thorns) | 棘刺 (Thorns), 号角 (Horn) | Ground ranged output, Phantom I.S. has some maps with very suitable positions | - | 召唤类 (Summoners) | 凯尔希 (Kal'tsit), 令 (Ling), 稀音 (Scene) | Self-contained ground blocking, some maps need priority deployment, summons can be used as blockers or fodder | - | 情报官 (Agents) | 晓歌 (Cantabile), 伊内丝 (Ines) | Can recover DP, provide side output, and can single cut | - | 浊心斯卡蒂 (Skadi Alter) | 浊心斯卡蒂 (Skadi the Corrupting Heart) | Decent healing under low pressure, but special range, some maps have suitable positions | - | 焰苇 (Reed Alter) | 焰影苇草 (Reed the Flame Shadow) | Commonly used opening operator in Sami I.S., combines healing and output, some maps have optimal positions | - | 玛恩纳 (SilverAsh) | 玛恩纳 (Closure), 银灰 (SilverAsh) | Ground large-area decisive output, can be deployed against bosses | - | 史尔特尔 (Surtr) | 史尔特尔 (Surtr) | Since Surtr always carries S3 at E2, field presence ability is almost zero, deployment priority is extremely low | - | 骰子 (Dice) | 骰子 (Dice) | In Mizuki I.S. the dice needs to be operated separately | + | Group | Operators | Features | + | :----------------------- | :----------------------------------------- | :--------------------------------------------------------------------------------------------------------------- | + | 益达 (Weathered) | 维什戴尔 (Weathered) | High ground DPS, prioritizing deployment can reduce pressure | + | 棘刺 (Thorns) | 棘刺 (Thorns), 号角 (Horn) | Ground ranged output, Phantom I.S. has some maps with very suitable positions | + | 召唤类 (Summoners) | 凯尔希 (Kal'tsit), 令 (Ling), 稀音 (Scene) | Self-contained ground blocking, some maps need priority deployment, summons can be used as blockers or fodder | + | 情报官 (Agents) | 晓歌 (Cantabile), 伊内丝 (Ines) | Can recover DP, provide side output, and can single cut | + | 浊心斯卡蒂 (Skadi Alter) | 浊心斯卡蒂 (Skadi the Corrupting Heart) | Decent healing under low pressure, but special range, some maps have suitable positions | + | 焰苇 (Reed Alter) | 焰影苇草 (Reed the Flame Shadow) | Commonly used opening operator in Sami I.S., combines healing and output, some maps have optimal positions | + | 玛恩纳 (SilverAsh) | 玛恩纳 (Closure), 银灰 (SilverAsh) | Ground large-area decisive output, can be deployed against bosses | + | 史尔特尔 (Surtr) | 史尔特尔 (Surtr) | Since Surtr always carries S3 at E2, field presence ability is almost zero, deployment priority is extremely low | + | 骰子 (Dice) | 骰子 (Dice) | In Mizuki I.S. the dice needs to be operated separately | ::: info Currently fixed to group unidentified ground crews behind the penultimate formation (other ground), and unidentified high-platform crews behind the penultimate formation (other high-platform) @@ -206,11 +207,11 @@ For beginner accounts: If 10 recruitments don't satisfy half the team's key oper "groups": [ "奶" // ("奶" = "Healers") (This indicates a need for 1 healer) ], - "threshold": 1 + "threshold": 1 } ... ] -} +} ``` ::: caution @@ -246,7 +247,7 @@ For example: Operator `焰影苇草` (Reed the Flame Shadow) may appear in both "skill_usage": 2, // Skill usage mode, refer to Combat Operation Protocol, difference is default is 1 if empty // (0 is don't use automatically, 1 is use when ready, 2 is use x times (x is set by "skill_times" field), 3 is not supported for now) "skill_times": 2, // Skill usage times, default is 1, effective when "skill_usage" field is 2 - "alternate_skill": 2, // Alternative skills used when there is no designated skill, usually 6-star operators who have not + "alternate_skill": 2, // Alternative skills used when there is no designated skill, usually 6-star operators who have not // E2'd and use 3 skills after promotion // (in this case, use skill 2 when skill 3 is not available) "alternate_skill_usage": 1, // Skill use mode for alternative skills (this field has not yet been implemented) @@ -262,7 +263,7 @@ For example: Operator `焰影苇草` (Reed the Flame Shadow) may appear in both // If the lineup completeness test is not passed, only key and 0 hope are recruited, saving hope. "is_start": true, // If true, the operator is a starter. Default to false if empty. If there is no start player in the team, // only start players and 0 hope players will be recruited, and user-filled players will be recruited. - "auto_retreat": 0, // Auto-retreat after a few full-seconds of deployment, takes effect when greater than 0, mainly used for specialists and vanguards, + "auto_retreat": 0, // Auto-retreat after a few full-seconds of deployment, takes effect when greater than 0, mainly used for specialists and vanguards, // since I.S. usually starts at 2x speed, it is recommended to set it to skill duration divided by 2 "recruit_priority_when_team_full": 850, // No need to set separately, recruitment priority when lineup completeness is met, default is recruitment priority -100 "promote_priority_when_team_full": 850, // No need to set separately, promotion priority when lineup completeness is met, default is E2 priority +300 @@ -299,7 +300,7 @@ For example: Operator `焰影苇草` (Reed the Flame Shadow) may appear in both 5. Add groups and operators as you see fit - When you add a new group, you can copy operators from existing groups. Refer to the ratings already given by the devs, and modify them on that basis. + When you add a new group, you can copy operators from existing groups. Refer to the ratings already given by the devs, and modify them on that basis. ## Integrated Strategy Step 2: Battle Logic @@ -310,93 +311,91 @@ For example: Operator `焰影苇草` (Reed the Flame Shadow) may appear in both (Effective when the combat logic file for the level name does not exist) 1. Perform basic combat operations based on the tile grid of the map + - MAA performs basic combat operations based on whether the grid on the map is a blue or red box, whether it's a high platform or ground, and whether it can be deployed or not. - - MAA performs basic combat operations based on whether the grid on the map is a blue or red box, whether it's a high platform or ground, and whether it can be deployed or not. + - MAA decides which job to use based on the name or number of the map only, and does not judge the map's **Standard**, **Emergency**, **Road Network**, **Foldartal Use**, etc. - - MAA decides which job to use based on the name or number of the map only, and does not judge the map's **Standard**, **Emergency**, **Road Network**, **Foldartal Use**, etc. - - - MAA does not judge **in combat the situation of undefined squares on the map**, e.g. the position of the altar in the `Taming Hut`, the `follower effect` of monsters coming out of the left side or the right side. + - MAA does not judge **in combat the situation of undefined squares on the map**, e.g. the position of the altar in the `Taming Hut`, the `follower effect` of monsters coming out of the left side or the right side. So in the future, you need to try to design a set of combat logic that can cope with **all the different scenarios of a map name** (the above-mentioned scenarios), and be careful of being hung up on the issue that this map operates in Emergency Mode. 2. MAA's Basic Battle Strategy -- Blocking the Blue Entry Point + 1. Ground Crews are preferably deployed on (or around) the grid of the Blue Box (why the grid, scroll down), orientated towards the Red box (auto-calculated), and are not deployed on the Red box - 1. Ground Crews are preferably deployed on (or around) the grid of the Blue Box (why the grid, scroll down), orientated towards the Red box (auto-calculated), and are not deployed on the Red box + 2. Prioritise the ground units before healers and ranged operators, in a circle from the blue box to the perimeter - 2. Prioritise the ground units before healers and ranged operators, in a circle from the blue box to the perimeter - - 3. It will keep deploying things that can be deployed according to the logic above (operators, summons, support items, etc.) + 3. It will keep deploying things that can be deployed according to the logic above (operators, summons, support items, etc.) ### Optimise basic combat strategies 1. Blue box Alternative - It's obviously not smart to just pile up your operators in front of the blue box, some levels have tiles where you can't get through, and the defence is very efficient here + It's obviously not smart to just pile up your operators in front of the blue box, some levels have tiles where you can't get through, and the defence is very efficient here - Or if there are levels with multiple blue boxes, and the MAA doesn't know which blue box corresponds to which red box, they may deploy randomly + Or if there are levels with multiple blue boxes, and the MAA doesn't know which blue box corresponds to which red box, they may deploy randomly - At this point, you'll need to open the [map wiki](https://map.ark-nights.com/areas?coord_override=maa) while imagining the battle in your head + At this point, you'll need to open the [map wiki](https://map.ark-nights.com/areas?coord_override=maa) while imagining the battle in your head - First switch the `Coordinate Display` to `MAA` in `Settings` + First switch the `Coordinate Display` to `MAA` in `Settings` - Then, based on your experience, find the coordinates and orientation of the points that need to be prioritised for defence, and write them into the `replacement_home` of the json. + Then, based on your experience, find the coordinates and orientation of the points that need to be prioritised for defence, and write them into the `replacement_home` of the json. - ```json - { - "stage_name": "蓄水池", // Level name ("蓄水池" = "Cistern") - "replacement_home": [ // Entry points (blue boxes replacement points), - // at least 1 to be complete - { - "location": [ // Grid coordinates, obtained from the map wiki - 6, - 4 - ], - "direction_Doc1": "Preferred direction, it doesn't mean it's definitely in that direction (the algorithm makes its own judgement)", - "direction_Doc2": "Default is none, i.e. there is no recommended direction, it is entirely up to the algorithm to decide", - "direction_Doc3": "none / left / right / up / down / 无 / 上 / 下 / 左 / 右", - "direction": "left" // (This indicates priority deployment of operators - // to the grid at coordinates 6,4 to the left.) - } - ], - ... - ``` + ```json + { + "stage_name": "蓄水池", // Level name ("蓄水池" = "Cistern") + "replacement_home": [ // Entry points (blue boxes replacement points), + // at least 1 to be complete + { + "location": [ // Grid coordinates, obtained from the map wiki + 6, + 4 + ], + "direction_Doc1": "Preferred direction, it doesn't mean it's definitely in that direction (the algorithm makes its own judgement)", + "direction_Doc2": "Default is none, i.e. there is no recommended direction, it is entirely up to the algorithm to decide", + "direction_Doc3": "none / left / right / up / down / 无 / 上 / 下 / 左 / 右", + "direction": "left" // (This indicates priority deployment of operators + // to the grid at coordinates 6,4 to the left.) + } + ], + ... + ``` - ::: tip - The blue box alternative will take effect when all steps in `deploy_plan` are completed but there are still operators to deploy in the waiting area, following the same logic as the general combat strategy - ::: + ::: tip + The blue box alternative will take effect when all steps in `deploy_plan` are completed but there are still operators to deploy in the waiting area, following the same logic as the general combat strategy + ::: 2. Deployment tile blacklist - There are points of priority for defence and points of priority for not deploying operators, such as where the fireball passes through, under the boss's feet, and some locations that are not good for output. + There are points of priority for defence and points of priority for not deploying operators, such as where the fireball passes through, under the boss's feet, and some locations that are not good for output. - At this point, we introduce `blacklist_location` to blacklist the tiles that we don't want MAA to deploy operators on. - ::: info - The tiles added here will not be used, even if they are included in the deployment strategy later on. - ::: + At this point, we introduce `blacklist_location` to blacklist the tiles that we don't want MAA to deploy operators on. + ::: info + The tiles added here will not be used, even if they are included in the deployment strategy later on. + ::: - ```json - ... - "blacklist_location_Doc": "This is an example of usage, not that the map 'Cistern' needs ban.", - "blacklist_location": [ // Locations where the deployment of the operators is prohibited - [ - 0, - 0 - ], - [ - 1, - 1 - ] - ], - ``` + ```json + ... + "blacklist_location_Doc": "This is an example of usage, not that the map 'Cistern' needs ban.", + "blacklist_location": [ // Locations where the deployment of the operators is prohibited + [ + 0, + 0 + ], + [ + 1, + 1 + ] + ], + ``` 3. Alternative map strategies - For example, if there is a monster in the blue box in Mizuki I.S. should we use the dice to ease the pressure of stacking monsters? + For example, if there is a monster in the blue box in Mizuki I.S. should we use the dice to ease the pressure of stacking monsters? - ```json - "not_use_dice_Doc": "When the Blue box operator is retreated does MAA need to use the dice. Defaults to false if empty", - "not_use_dice": false, - ``` + ```json + "not_use_dice_Doc": "When the Blue box operator is retreated does MAA need to use the dice. Defaults to false if empty", + "not_use_dice": false, + ``` ### Or is it an Emergency Operation? It's time to show your true white skills - customised combat strategies @@ -408,69 +407,68 @@ There is no need to set up too many customised plans when there is a problem. It 1. Deployment of operators using groups - ```json - "deploy_plan": [ // Deployment logic: order from top-to-bottom, left-to-right - // Tries to deploy the first operator it finds, or skips it if it doesn't. - { - "groups": ["百嘉", "基石", "地面C", "号角", "挡人先锋"], // Looks for operators from these groups - // ("百嘉" = "Gavial Alter", "基石" = "Cornerstone", "地面C" = "Ground C", "号角" = "Horn", "挡人先锋" = "Blocking Vanguard") - "location": [ 6, 4 ], // Deploys the first agent it finds to coordinates 6,4 and faces left. - "direction": "left", // If it doesn't find it, proceed to the next deployment operation. - }, - { - "groups": [ "召唤" ], // ("召唤" = "Summoner") - "location": [ 6, 3 ], - "direction": "left" - }, - { - "groups": [ "单奶", "群奶" ], // ("单奶" = "Single-target Healer", "群奶" = "AoE Healer") - "location": [ 6, 2 ], - "direction": "down" - } - ] - ``` + ```json + "deploy_plan": [ // Deployment logic: order from top-to-bottom, left-to-right + // Tries to deploy the first operator it finds, or skips it if it doesn't. + { + "groups": ["百嘉", "基石", "地面C", "号角", "挡人先锋"], // Looks for operators from these groups + // ("百嘉" = "Gavial Alter", "基石" = "Cornerstone", "地面C" = "Ground C", "号角" = "Horn", "挡人先锋" = "Blocking Vanguard") + "location": [ 6, 4 ], // Deploys the first agent it finds to coordinates 6,4 and faces left. + "direction": "left", // If it doesn't find it, proceed to the next deployment operation. + }, + { + "groups": [ "召唤" ], // ("召唤" = "Summoner") + "location": [ 6, 3 ], + "direction": "left" + }, + { + "groups": [ "单奶", "群奶" ], // ("单奶" = "Single-target Healer", "群奶" = "AoE Healer") + "location": [ 6, 2 ], + "direction": "down" + } + ] + ``` - ::: info - MAA flattens all deployment commands and then executes the highest-priority deployment operations - Example: deploys [ "百嘉" (Gavial), "基石" (Cornerstone), "地面C" (Ground C)] on [6,4], deploys [ "基石" (Cornerstone), "地面C" (Ground C)] on [6,3], then MAA will flatten the deployment commands to [ "百嘉" (Gavial), "基石" (Cornerstone), "地面C" (Ground C), "基石" (Cornerstone), "地面C" (Ground C)] - If a "百嘉" (Gavial) operator on [6,4] is retreated during battle, the "基石" (Cornerstone) operator in hand, if available, will be deployed on [6,4], instead of [6,3] + ::: info + MAA flattens all deployment commands and then executes the highest-priority deployment operations + Example: deploys [ "百嘉" (Gavial), "基石" (Cornerstone), "地面C" (Ground C)] on [6,4], deploys [ "基石" (Cornerstone), "地面C" (Ground C)] on [6,3], then MAA will flatten the deployment commands to [ "百嘉" (Gavial), "基石" (Cornerstone), "地面C" (Ground C), "基石" (Cornerstone), "地面C" (Ground C)] + If a "百嘉" (Gavial) operator on [6,4] is retreated during battle, the "基石" (Cornerstone) operator in hand, if available, will be deployed on [6,4], instead of [6,3] - This means that from a macro perspective, after each deployment action is completed, it will start checking for executable strategies from the beginning (the current step's position has no already placed operators, and there are operators in the deployment area belonging to this step's operator group) - ::: + This means that from a macro perspective, after each deployment action is completed, it will start checking for executable strategies from the beginning (the current step's position has no already placed operators, and there are operators in the deployment area belonging to this step's operator group) + ::: - ::: tip - Some commonly used operator group usages: + ::: tip + Some commonly used operator group usages: + 1. In many operations, the main defensive point combination is [ "地面阻挡" (Ground Blocking), "处决者" (Executor), "其他地面" (Other Ground)], which means when the main tanking operator dies, it will try to use an executor to delay the CD; when there's too much survival pressure on this point, consider using [ "重装" (Heavy Defender), "地面阻挡" (Ground Blocking), "处决者" (Executor), "炮灰" (Fodder), "其他地面" (Other Ground)]; for positions behind defenders, prioritize [ "地面远程" (Ground Ranged), "地面阻挡" (Ground Blocking), "处决者" (Executor), "其他地面" (Other Ground)]; to purely attract aggro or sacrifice, use [ "炮灰" (Fodder), "障碍物" (Obstacles), "其他地面" (Other Ground)] - 1. In many operations, the main defensive point combination is [ "地面阻挡" (Ground Blocking), "处决者" (Executor), "其他地面" (Other Ground)], which means when the main tanking operator dies, it will try to use an executor to delay the CD; when there's too much survival pressure on this point, consider using [ "重装" (Heavy Defender), "地面阻挡" (Ground Blocking), "处决者" (Executor), "炮灰" (Fodder), "其他地面" (Other Ground)]; for positions behind defenders, prioritize [ "地面远程" (Ground Ranged), "地面阻挡" (Ground Blocking), "处决者" (Executor), "其他地面" (Other Ground)]; to purely attract aggro or sacrifice, use [ "炮灰" (Fodder), "障碍物" (Obstacles), "其他地面" (Other Ground)] + 2. High ground position combinations commonly use [ "高台输出" (Ranged DPS), "其他高台" (Other High Ground)], if you want any high ground to be placed you can use [ "高台输出" (Ranged DPS), "狙击" (Sniper), "辅助" (Supporter), "盾法" (Shield Caster), "其他高台" (Other High Ground)] - 2. High ground position combinations commonly use [ "高台输出" (Ranged DPS), "其他高台" (Other High Ground)], if you want any high ground to be placed you can use [ "高台输出" (Ranged DPS), "狙击" (Sniper), "辅助" (Supporter), "盾法" (Shield Caster), "其他高台" (Other High Ground)] - - 3. Some ground positions are suitable for both SilverAsh and ground trap operators [ "玛恩纳" (SilverAsh), "地刺" (Ground Traps)] - ::: + 3. Some ground positions are suitable for both SilverAsh and ground trap operators [ "玛恩纳" (SilverAsh), "地刺" (Ground Traps)] + ::: 2. Deployment of operators at a point in time - ::: tip - Suitable for certain single-cutting operators or usage scenarios that require cannon fodder - ::: + ::: tip + Suitable for certain single-cutting operators or usage scenarios that require cannon fodder + ::: - ```json - "deploy_plan": [ - { - "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], - // ("异德" = "Strange Virtue", "刺客" = "Assassin", "挡人先锋" = "Blocking Vanguard", "其他地面" = "Other Ground") - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 0, 3 ] // This operation is only performed when the number of kills is 0 - 3 - }, - { - "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 6, 10 ] - }, - ... - ] - ``` + ```json + "deploy_plan": [ + { + "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], + // ("异德" = "Strange Virtue", "刺客" = "Assassin", "挡人先锋" = "Blocking Vanguard", "其他地面" = "Other Ground") + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 0, 3 ] // This operation is only performed when the number of kills is 0 - 3 + }, + { + "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 6, 10 ] + }, + ... + ] + ``` 3. Retrieval of the operators at some point ::: tip @@ -479,64 +477,64 @@ There is no need to set up too many customised plans when there is a problem. It Deployment and retreat commands for the same position should have non-overlapping condition numbers, otherwise it will instantly retreat after deploying ::: - ```json - "retreat_plan": [ // Retrieval targets at specific points in time - { - "location": [ 4, 1 ], - "condition": [ 7, 8 ] // At 7 - 8 kills, remove operator on [4,1], skip if there are none. - } - ] - ``` + ```json + "retreat_plan": [ // Retrieval targets at specific points in time + { + "location": [ 4, 1 ], + "condition": [ 7, 8 ] // At 7 - 8 kills, remove operator on [4,1], skip if there are none. + } + ] + ``` 4. Disable a skill at a certain point in time (to do) 5. Additional fields (not recommended) - ```json - "role_order_Doc": "Operator type deployment order, the unspecified parts will be filled in with the order of Guard, Vanguard, Medic, Defender, Sniper, Caster, Supporter, Specialist, Summoner, and so on.", - "role_order": [ // Not recommended, please configure the deploy_plan field. - "warrior", - "pioneer", - "medic", - "tank", - "sniper", - "caster", - "support", - "special", - "drone" - ], - "force_air_defense_when_deploy_blocking_num_Doc": "When there are 10000 blocking units on the field, it will start to force deploying a total of 1 pair of empty units (fill in or not will not affect the normal deployment logic), during this period, it does not prohibit the deployment of medical units (no default is false).", - "force_air_defense_when_deploy_blocking_num": { // Not recommended, please configure the deploy_plan field. - "melee_num": 10000, - "air_defense_num": 1, - "ban_medic": false - }, - "force_deploy_direction_Doc": "These points force deployment directions for certain occupation", - "force_deploy_direction": [ // Not recommended, please configure the deploy_plan field. - { - "location": [ - 1, - 1 - ], - "role_Doc": "Application of mandatory orientation to the occupation entered", - "role": [ - "warrior", - "pioneer" - ], - "direction": "up" - }, - { - "location": [ - 3, - 1 - ], - "role": [ - "sniper" - ], - "direction": "left" - } - ], - ``` + ```json + "role_order_Doc": "Operator type deployment order, the unspecified parts will be filled in with the order of Guard, Vanguard, Medic, Defender, Sniper, Caster, Supporter, Specialist, Summoner, and so on.", + "role_order": [ // Not recommended, please configure the deploy_plan field. + "warrior", + "pioneer", + "medic", + "tank", + "sniper", + "caster", + "support", + "special", + "drone" + ], + "force_air_defense_when_deploy_blocking_num_Doc": "When there are 10000 blocking units on the field, it will start to force deploying a total of 1 pair of empty units (fill in or not will not affect the normal deployment logic), during this period, it does not prohibit the deployment of medical units (no default is false).", + "force_air_defense_when_deploy_blocking_num": { // Not recommended, please configure the deploy_plan field. + "melee_num": 10000, + "air_defense_num": 1, + "ban_medic": false + }, + "force_deploy_direction_Doc": "These points force deployment directions for certain occupation", + "force_deploy_direction": [ // Not recommended, please configure the deploy_plan field. + { + "location": [ + 1, + 1 + ], + "role_Doc": "Application of mandatory orientation to the occupation entered", + "role": [ + "warrior", + "pioneer" + ], + "direction": "up" + }, + { + "location": [ + 3, + 1 + ], + "role": [ + "sniper" + ], + "direction": "left" + } + ], + ``` ::: info When MAA cannot find a customized combat strategy for the current level, it will automatically execute the general combat strategy. @@ -634,7 +632,7 @@ The Encounter options can be modified to guide MAA towards special endings // (does not affect the operation, useful for convenient sorting) "no": 167 // Collectible number (can be found in the wiki, does not affect the operation) }, - + ... { "name": "扩散之手", // ("扩散之手" = "Hand of Diffusion") @@ -643,7 +641,7 @@ The Encounter options can be modified to guide MAA towards special endings // you will try to buy the Hand of Diffusion when you encounter it) ], "effect": "【扩散术师】、【链术师】和【轰击术师】每对一个单位造成伤害就回复2点技力值", // ("[Diffusion Artist], [Chain Artist], and [Blast Artist] regain 2 SP for each unit they deal damage to.") - "no": 136 + "no": 136 }, ... @@ -654,7 +652,7 @@ The Encounter options can be modified to guide MAA towards special endings // you will try to buy a Halberd-Breaker when you encounter it) ], "effect": "所有【近卫】干员的防御力-40%,但攻击力+40%,攻击速度+30", // ("All [Guard] Operators members have -40% Defence, but +40% Attack Power and +30% Attack Speed.") - "no": 16 + "no": 16 }, ... @@ -761,7 +759,7 @@ Here is an example task configuration for farming hidden Collapsal Paradigms: "squad": "远程战术分队", // ("远程战术分队" = "Ranged Tactics Squad") "roles": "稳扎稳打", // ("稳扎稳打" = "Steady Approach") "core_char": "维什戴尔", // ("维什戴尔" = "Weathered") - "expected_collapsal_paradigms": ["目空一些", "睁眼瞎", "图像损坏", "一抹黑"] + "expected_collapsal_paradigms": ["目空一些", "睁眼瞎", "图像损坏", "一抹黑"] // ("目空一些" = "Blank Somewhat", "睁眼瞎" = "Blind Eye", "图像损坏" = "Image Distortion", "一抹黑" = "Pitch Black") } ``` diff --git a/docs/en-us/protocol/integration.md b/docs/en-us/protocol/integration.md index 51f2ada92c..cfc83bb57b 100644 --- a/docs/en-us/protocol/integration.md +++ b/docs/en-us/protocol/integration.md @@ -22,22 +22,22 @@ Appends a task. #### Return Value - `TaskId` - The task ID if the task is successfully appended, for the following configuration; - 0 if the task is not successfully appended. + The task ID if the task is successfully appended, for the following configuration; + 0 if the task is not successfully appended. #### Parameter Description - `AsstHandle handle` - Instance handle + Instance handle - `const char* type` - Task type + Task type - `const char* params` - Task parameters in JSON + Task parameters in JSON ##### List of Task Types - `StartUp` - Start-up + Start-up ```json5 // Corresponding task parameters @@ -54,7 +54,7 @@ Appends a task. ``` - `CloseDown` - Close Game Client + Close Game Client ```json5 // Corresponding task parameters @@ -66,7 +66,7 @@ Appends a task. ``` - `Fight` - Operation + Operation ```json5 // Corresponding task parameters @@ -105,7 +105,7 @@ Appends a task. Supports some of the special stages, please refer to [autoLocalization example](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/tools/AutoLocalization/example/en-us.xaml#L260). - `Recruit` - Recruitment + Recruitment ```json5 // Corresponding task parameters @@ -149,7 +149,7 @@ Supports some of the special stages, please refer to [autoLocalization example]( ``` - `Infrast` - Infrastructure shifting + Infrastructure shifting ```json5 { @@ -182,8 +182,8 @@ Supports some of the special stages, please refer to [autoLocalization example]( ``` - `Mall` - Collecting Credits and auto-purchasing. - Will buy items in order following `buy_first` list, buy other items from left to right ignoring items in `blacklist`, and buy other items from left to right ignoring the `blacklist` while credit overflows. + Collecting Credits and auto-purchasing. + Will buy items in order following `buy_first` list, buy other items from left to right ignoring items in `blacklist`, and buy other items from left to right ignoring the `blacklist` while credit overflows. ```json5 // Corresponding task parameters @@ -209,7 +209,7 @@ Supports some of the special stages, please refer to [autoLocalization example]( ``` - `Award` - Collecting various rewards + Collecting various rewards ```json5 // Corresponding task parameters @@ -225,7 +225,7 @@ Supports some of the special stages, please refer to [autoLocalization example]( ``` - `Roguelike` - Integrated Strategies + Integrated Strategies ```json5 // Task parameters @@ -250,7 +250,7 @@ Supports some of the special stages, please refer to [autoLocalization example]( // 7 - Deep Dive rewards farming, same as mode 0 except for specific mode adaptations "squad": string, // Starting squad name, optional, default is "指挥分队" (Command Squad); "roles": string, // Starting role group, optional, default is "取长补短" (Complementary Strength); - "core_char": string, // Starting operator name, optional; supports only single operator **in Chinese**, regardless of server; + "core_char": string, // Starting operator name, optional; supports only single operator **in Chinese**, regardless of server; // leave empty or set to "" to auto-select based on level "use_support": bool, // Whether the starting operator is a support operator, optional, default is false "use_nonfriend_support": bool, // Whether non-friend support operators are allowed, optional, default is false; only effective when `use_support` is true @@ -309,7 +309,7 @@ Supports some of the special stages, please refer to [autoLocalization example]( For specific information about the Collapsal Paradigm farming feature, please refer to [Integrated Strategy Schema](./integrated-strategy-schema.md#sami-integrated-strategy-collapsal-paradigms) - `Copilot` - Auto combat feature + Auto combat feature ```json5 { @@ -322,7 +322,7 @@ For specific information about the Collapsal Paradigm farming feature, please re For more details about auto-combat JSON, please refer to [Combat Operation Protocol](./copilot-schema.md) - `SSSCopilot` - Auto combat feature for Stationary Security Service + Auto combat feature for Stationary Security Service ```json5 { @@ -335,7 +335,7 @@ For more details about auto-combat JSON, please refer to [Combat Operation Proto For more details about Stationary Security Service JSON, please refer to [SSS Schema](./sss-schema.md) - `Depot` - Depot recognition + Depot recognition ```json5 // Corresponding task parameters @@ -345,7 +345,7 @@ For more details about Stationary Security Service JSON, please refer to [SSS Sc ``` - `OperBox` - Operator box recognition + Operator box recognition ```json5 // Corresponding task parameters @@ -355,7 +355,7 @@ For more details about Stationary Security Service JSON, please refer to [SSS Sc ``` - `Reclamation` - Reclamation Algorithm + Reclamation Algorithm ```json5 { @@ -370,7 +370,7 @@ For more details about Stationary Security Service JSON, please refer to [SSS Sc "tools_to_craft": [ string, // Automatically crafted items, optional, glow stick by default ... - ] + ] // Suggested to fill in the substring "increment_mode": int, // Click type, optional. 0 by default // 0 - Rapid Click @@ -380,7 +380,7 @@ For more details about Stationary Security Service JSON, please refer to [SSS Sc ``` - `Custom` - Custom Task + Custom Task ```json5 { @@ -394,7 +394,7 @@ For more details about Stationary Security Service JSON, please refer to [SSS Sc ``` - `SingleStep` - Single-step task (currently only supports copilot) + Single-step task (currently only supports copilot) ```json5 { @@ -412,7 +412,7 @@ For more details about Stationary Security Service JSON, please refer to [SSS Sc ``` - `VideoRecognition` - Video recognition, currently only supports operation (combat) video + Video recognition, currently only supports operation (combat) video ```json5 { @@ -436,17 +436,17 @@ Set task parameters #### Return Value - `bool` - Whether the parameters are successfully set. + Whether the parameters are successfully set. #### Parameter Description - `AsstHandle handle` - Instance handle + Instance handle - `TaskId task` - Task ID, the return value of `AsstAppendTask` + Task ID, the return value of `AsstAppendTask` - `const char* params` - Task parameter in JSON, same as `AsstAppendTask` - For those fields that do not mention "Editing in run-time is not supported" can be changed during run-time. Otherwise these changes will be ignored when the task is running. + Task parameter in JSON, same as `AsstAppendTask` + For those fields that do not mention "Editing in run-time is not supported" can be changed during run-time. Otherwise these changes will be ignored when the task is running. ### `AsstSetStaticOption` @@ -463,14 +463,14 @@ Set process-level parameters #### Return Value - `bool` - Is the setup successful + Is the setup successful #### Parameter Description - `AsstStaticOptionKey key` - key + key - `const char* value` - value + value ##### List of Key and value @@ -491,16 +491,16 @@ Set instance-level parameters #### Return Value - `bool` - Is the setup successful + Is the setup successful #### Parameter Description - `AsstHandle handle` - handle + handle - `AsstInstanceOptionKey key` - key + key - `const char* value` - value + value ##### List of Key and value diff --git a/docs/en-us/protocol/remote-control-schema.md b/docs/en-us/protocol/remote-control-schema.md index 963eecc6ab..9405b209cd 100644 --- a/docs/en-us/protocol/remote-control-schema.md +++ b/docs/en-us/protocol/remote-control-schema.md @@ -88,6 +88,7 @@ The endpoint should be reentrant and repeatedly return tasks to execute, as MAA - Settings-[SettingsName] task types include Settings-ConnectionAddress, Settings-Stage1 - Settings series tasks still execute sequentially rather than immediately, queuing behind previous tasks - Multiple immediate execution tasks also execute in issued order, though since these tasks execute quickly, their order generally doesn't matter + ::: ## Task Reporting Endpoint diff --git a/docs/en-us/protocol/task-schema.md b/docs/en-us/protocol/task-schema.md index 8e68163b21..66855c9fc8 100644 --- a/docs/en-us/protocol/task-schema.md +++ b/docs/en-us/protocol/task-schema.md @@ -99,7 +99,7 @@ Please note that JSON files do not support comments. The comments in this docume "highResolutionSwipeFix": false, // Optional, whether to enable high-resolution swipe fix // Currently only needed for stage navigation which doesn't use unity swipe method // Default is false - + /* Fields below only valid when algorithm is MatchTemplate */ "template": "xxx.png", // Optional, image file to match, can be string or string list @@ -165,7 +165,7 @@ Please note that JSON files do not support comments. The comments in this docume /* Fields below only valid when algorithm is JustReturn and action is Input */ "inputText": "A string text.", // Required, text to input as string - + /* Fields below only valid when algorithm is FeatureMatch */ "template": "xxx.png", // Optional, image file to match, can be string or string list @@ -189,14 +189,14 @@ Please note that JSON files do not support comments. The comments in this docume Task list type fields (`sub`, `next`, `onErrorNext`, `exceededNext`, `reduceOtherTimes`) support expression calculations. -| Symbol | Meaning | Example | -| :---------: | :---------------------------------------------------------: | :---------------------------------------: | -| `@` | `@`-type Task | `Fight@ReturnTo` | -| `#` (unary) | Virtual task | `#self` | -| `#` (binary)| Virtual task | `StartUpThemes#next` | -| `*` | Repeat tasks | `(ClickCornerAfterPRTS+ClickCorner)*5` | -| `+` | Task list merge (in next-type attributes, only first occurrence of same-name tasks kept) | `A+B` | -| `^` | Task list difference (in first but not second, order preserved) | `(A+A+B+C)^(A+B+D)` (result is `C`) | +| Symbol | Meaning | Example | +| :----------: | :--------------------------------------------------------------------------------------: | :------------------------------------: | +| `@` | `@`-type Task | `Fight@ReturnTo` | +| `#` (unary) | Virtual task | `#self` | +| `#` (binary) | Virtual task | `StartUpThemes#next` | +| `*` | Repeat tasks | `(ClickCornerAfterPRTS+ClickCorner)*5` | +| `+` | Task list merge (in next-type attributes, only first occurrence of same-name tasks kept) | `A+B` | +| `^` | Task list difference (in first but not second, order preserved) | `(A+A+B+C)^(A+B+D)` (result is `C`) | Operators `@`, `#`, `*`, `+`, `^` have precedence: `#` (unary) > `@` = `#` (binary) > `*` > `+` = `^`. @@ -204,31 +204,31 @@ Operators `@`, `#`, `*`, `+`, `^` have precedence: `#` (unary) > `@` = `#` (bina ### Template Task -**Template tasks** include derived tasks and `@`-type tasks. The core of the template task can be understood as **modifying the default values of fields** based on the *base task*. +**Template tasks** include derived tasks and `@`-type tasks. The core of the template task can be understood as **modifying the default values of fields** based on the _base task_. #### Derived Task -Tasks with the `baseTask` field are derived tasks, and the task corresponding to the `baseTask` field is referred to as its *base task* of this derived task. For a derived task, +Tasks with the `baseTask` field are derived tasks, and the task corresponding to the `baseTask` field is referred to as its _base task_ of this derived task. For a derived task, 1. If it is an template matching task, the default value for the `template` field remains `"TaskName.png"`; -2. If the `algorithm` field differs from its *base task*, the derived class parameters are not inherited (only parameters defined in `TaskInfo` are inherited); -3. The default values for all other fields are the corresponding fields of its *base task*. +2. If the `algorithm` field differs from its _base task_, the derived class parameters are not inherited (only parameters defined in `TaskInfo` are inherited); +3. The default values for all other fields are the corresponding fields of its _base task_. #### Implicit `@`-type Task -If task `"A"` exists and there is not a task directly defined in any task file such as `"B@A"`, it is an implicit `@`-type task, and task `"A"` is called the *base task* of task `"B@A"`. For an implicit `@`-type task, +If task `"A"` exists and there is not a task directly defined in any task file such as `"B@A"`, it is an implicit `@`-type task, and task `"A"` is called the _base task_ of task `"B@A"`. For an implicit `@`-type task, 1. The default values for task list type fields (`sub`, `next`, `onErrorNext`, `exceededNext`, `reduceOtherTimes`) are set to the base task's corresponding fields with the `B@` prefix directly appended (if the task name starts with `#`, the `B` prefix is appended); -2. The default values for all other fields (including the `template` field) are the corresponding fields of its *base task*. +2. The default values for all other fields (including the `template` field) are the corresponding fields of its _base task_. #### Explicit `@`-type Task -If task `"A"` exists and there is a task directly defined in the task file such as `"B@A"`, it is an explicit `@`-type task, and task `"A"` is called the *base task* of task `"B@A"`. For an explicit `@`-type task, +If task `"A"` exists and there is a task directly defined in the task file such as `"B@A"`, it is an explicit `@`-type task, and task `"A"` is called the _base task_ of task `"B@A"`. For an explicit `@`-type task, 1. The default values for task list type fields (`sub`, `next`, `onErrorNext`, `exceededNext`, `reduceOtherTimes`) are set to the base task's corresponding fields with the `B@` prefix directly appended (if the task name starts with `#`, the `B` prefix is appended); 2. If it is an template matching task, the default value for the `template` field remains `"TaskName.png"`; -3. If the `algorithm` field differs from its *base task*, the derived class parameters are not inherited (only parameters defined in `TaskInfo` are inherited); -4. The default values for all other fields are the corresponding fields of its *base task*. +3. If the `algorithm` field differs from its _base task_, the derived class parameters are not inherited (only parameters defined in `TaskInfo` are inherited); +4. The default values for all other fields are the corresponding fields of its _base task_. ### Virtual Task (`#`-type Task) @@ -236,18 +236,18 @@ Virtual tasks are tasks of the form `"#{sharp_type}"` or `"B#{sharp_type}"`, whe Virtual tasks can be divided into **command virtual tasks** (`#none` / `#self` / `#back`) and **field virtual tasks** (`#next`, etc.). -| Virtual Task Type | Meaning | Simple example | -|:---------:|:---:|:--------:| -| none | Empty Task | Skip directly1
`"A": {"next": ["#none", "T1"]}` is interpreted as `"A": {"next": ["T1"]}`
`"A#none + T1"` is interpreted as `"T1"` | -| self | Current Task Name | `"A": {"next": "#self"}` in `"#self"` is interpreted as `"A"`
`"B": {"next": "A@B@C#self"}` in `"A@B@C#self"` is interpreted as `"B"`.2 | -| back | # Preceding task name | `"A@B#back"` is interpreted as `"A@B"`
`"#back"` will be skipped if it appears directly3 | -| next, sub, etc. | # The field corresponding to the previous task name | Take `next` for example:
`"A#next"` is interpreted as `Task.get("A")->next`
`"#next"` will be skipped if it appears directly | +| Virtual Task Type | Meaning | Simple example | +| :---------------: | :-------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------: | +| none | Empty Task | Skip directly1
`"A": {"next": ["#none", "T1"]}` is interpreted as `"A": {"next": ["T1"]}`
`"A#none + T1"` is interpreted as `"T1"` | +| self | Current Task Name | `"A": {"next": "#self"}` in `"#self"` is interpreted as `"A"`
`"B": {"next": "A@B@C#self"}` in `"A@B@C#self"` is interpreted as `"B"`.2 | +| back | # Preceding task name | `"A@B#back"` is interpreted as `"A@B"`
`"#back"` will be skipped if it appears directly3 | +| next, sub, etc. | # The field corresponding to the previous task name | Take `next` for example:
`"A#next"` is interpreted as `Task.get("A")->next`
`"#next"` will be skipped if it appears directly | -*Note1: `"#none"` generally used in conjunction with the template task to add prefixes, or used in the `baseTask` field to avoid unnecessary fields in multi-file inheritance.* +_Note1: `"#none"` generally used in conjunction with the template task to add prefixes, or used in the `baseTask` field to avoid unnecessary fields in multi-file inheritance._ -*Note2: `"XXX#self"` has the same meaning as `"#self"`.* +_Note2: `"XXX#self"` has the same meaning as `"#self"`._ -*Note3: When several tasks have `"next": [ "#back" ]`, `"T1@T2@T3"` represents executing `T3`, `T2`, and `T1` in sequence.* +_Note3: When several tasks have `"next": [ "#back" ]`, `"T1@T2@T3"` represents executing `T3`, `T2`, and `T1` in sequence._ ### Multi-File Task @@ -260,86 +260,86 @@ If a task defined in a later loaded task file (e.g. `tasks.json` for foreign ser - Derived task example (field `baseTask`) - Assume the following two tasks are defined: + Assume the following two tasks are defined: - ```json - "Return": { - "action": "ClickSelf", - "next": [ "Stop" ] - }, - "Return2": { - "baseTask": "Return" - }, - ``` + ```json + "Return": { + "action": "ClickSelf", + "next": [ "Stop" ] + }, + "Return2": { + "baseTask": "Return" + }, + ``` - The parameters of the `"Return2"` task are directly inherited from the `"Return"` task, and actually include the following parameters: + The parameters of the `"Return2"` task are directly inherited from the `"Return"` task, and actually include the following parameters: - ```json - "Return2": { - "algorithm": "MatchTemplate", // Directly inherited - "template": "Return2.png", // "TaskName.png" - "action": "ClickSelf", // Directly inherited - "next": [ "Stop" ] // Directly inherited, without any prefix compared to the Template Task - } - ``` + ```json + "Return2": { + "algorithm": "MatchTemplate", // Directly inherited + "template": "Return2.png", // "TaskName.png" + "action": "ClickSelf", // Directly inherited + "next": [ "Stop" ] // Directly inherited, without any prefix compared to the Template Task + } + ``` - `@`-type task example - Assume that a task `"A"` with the following parameters is defined: + Assume that a task `"A"` with the following parameters is defined: - ```json - "A": { - "template": "A.png", - ..., - "next": [ "N1", "#back" ] - }, - ``` + ```json + "A": { + "template": "A.png", + ..., + "next": [ "N1", "#back" ] + }, + ``` - If the task `"B@A"` is not directly defined, then the task `"B@A"` actually has the following parameters: + If the task `"B@A"` is not directly defined, then the task `"B@A"` actually has the following parameters: - ```json - "B@A": { - "template": "A.png", - ..., - "next": [ "B@N1", "B#back" ] - } - ``` + ```json + "B@A": { + "template": "A.png", + ..., + "next": [ "B@N1", "B#back" ] + } + ``` - If the task `"B@A"` is defined as `"B@A": {}`, then the task `"B@A"` actually has the following parameters: + If the task `"B@A"` is defined as `"B@A": {}`, then the task `"B@A"` actually has the following parameters: - ```json - "B@A": { - "template": "B@A.png", - ..., - "next": [ "B@N1", "B#back" ] - } - ``` + ```json + "B@A": { + "template": "B@A.png", + ..., + "next": [ "B@N1", "B#back" ] + } + ``` - Virtual task example - ```json - { - "A": { "next": ["N1", "N2"] }, - "C": { "next": ["B@A#next"] }, + ```json + { + "A": { "next": ["N1", "N2"] }, + "C": { "next": ["B@A#next"] }, - "Loading": { - "next": ["#self", "#next", "#back"] - }, - "B": { - "next": ["Other", "B@Loading"] - } - } - ``` + "Loading": { + "next": ["#self", "#next", "#back"] + }, + "B": { + "next": ["Other", "B@Loading"] + } + } + ``` - Results in: + Results in: - ```cpp - Task.get("C")->next = { "B@N1", "B@N2" }; + ```cpp + Task.get("C")->next = { "B@N1", "B@N2" }; - Task.get("B@Loading")->next = { "B@Loading", "Other", "B" }; - Task.get("Loading")->next = { "Loading" }; - Task.get_raw("B@Loading")->next = { "B#self", "B#next", "B#back" }; - ``` + Task.get("B@Loading")->next = { "B@Loading", "Other", "B" }; + Task.get("Loading")->next = { "Loading" }; + Task.get_raw("B@Loading")->next = { "B#self", "B#next", "B#back" }; + ``` ### Precautions @@ -347,41 +347,41 @@ If the tasks defined in the task list type field (`next`, etc.) contain low-prio 1. Special cases caused by the order of operations between `@` and double `#` - ```json - { - "A": { "next": ["N0"] }, - "B": { "next": ["A#next"] }, - "C@A": { "next": ["N1"] } - } - ``` + ```json + { + "A": { "next": ["N0"] }, + "B": { "next": ["A#next"] }, + "C@A": { "next": ["N1"] } + } + ``` - In the above case, `"C@B" -> next` (i.e., `C@A#next`) is `[ "N1" ]` rather than `[ "C@N0" ]`. + In the above case, `"C@B" -> next` (i.e., `C@A#next`) is `[ "N1" ]` rather than `[ "C@N0" ]`. 2. Special cases caused by the order of operations between `@` and `+` - ```json - { - "A": { "next": ["#back + N0"] }, - "B@A": {} - } - ``` + ```json + { + "A": { "next": ["#back + N0"] }, + "B@A": {} + } + ``` - In the above case, + In the above case, - ```cpp - Task.get("A")->next = { "N0" }; + ```cpp + Task.get("A")->next = { "N0" }; - Task.get_raw("B@A")->next = { "B#back + N0" }; - Task.get("B@A")->next = { "B", "N0" }; // Note that it is not [ "B", "B@N0" ] - ``` + Task.get_raw("B@A")->next = { "B#back + N0" }; + Task.get("B@A")->next = { "B", "N0" }; // Note that it is not [ "B", "B@N0" ] + ``` - In fact, you can use this feature to avoid adding unnecessary prefixes by simply defining + In fact, you can use this feature to avoid adding unnecessary prefixes by simply defining - ```json - { - "A": { "next": ["#none + N0"] } - } - ``` + ```json + { + "A": { "next": ["#none + N0"] } + } + ``` ## Runtime Task Modification diff --git a/docs/en-us/readme.md b/docs/en-us/readme.md index b1fc4d20a6..35651ae50f 100644 --- a/docs/en-us/readme.md +++ b/docs/en-us/readme.md @@ -12,6 +12,7 @@ dir: ![MAA Logo =256x256](/images/maa-logo_512x512.png) + # MAA ![C++](https://img.shields.io/badge/C++-20-%2300599C?logo=cplusplus) @@ -25,7 +26,7 @@ An Arknights assistant Based on image recognition technology, complete all daily tasks with one click! -Development actively in progress ✿✿ヽ(°▽°)ノ✿ +Development actively in progress ✿✿ヽ(°▽°)ノ✿ ::: @@ -194,9 +195,9 @@ User Exchange QQ Groups: [MAA Usage & Arknights Exchange QQ Group](https://api.m Discord Server: [Invite Link](https://discord.gg/23DfZ9uA4V) User Exchange Telegram Group: [Telegram Group](https://t.me/+Mgc2Zngr-hs3ZjU1) Auto-battle JSON strategy sharing: [prts.plus](https://prts.plus) -Bilibili Live: [MrEO Live](https://live.bilibili.com/2808861) coding streams & [MAA-Official Live](https://live.bilibili.com/27548877) gaming/chat +Bilibili Live: [MrEO Live](https://live.bilibili.com/2808861) coding streams & [MAA-Official Live](https://live.bilibili.com/27548877) gaming/chat Technical Group (non-Arknights, no casual chat): [Internal Competition Hell! (QQ Group)](https://jq.qq.com/?_wv=1027&k=ypbzXcA2) -Developer Group: [QQ Group](https://jq.qq.com/?_wv=1027&k=JM9oCk3C) +Developer Group: [QQ Group](https://jq.qq.com/?_wv=1027&k=JM9oCk3C) If you find the software helpful, please give us a Star! ~ (the small star at the top right of the webpage), that's the biggest support diff --git a/docs/ja-jp/develop/development.md b/docs/ja-jp/develop/development.md index a5b10f6274..069cc10758 100644 --- a/docs/ja-jp/develop/development.md +++ b/docs/ja-jp/develop/development.md @@ -17,48 +17,46 @@ icon: iconoir:developer 2. [MAA メインリポジトリ](https://github.com/MaaAssistantArknights/MaaAssistantArknights)を開き、`Fork` → `Create fork` をクリック 3. 自身のリポジトリの dev ブランチをクローン(サブモジュール含む) - ```bash - git clone --recurse-submodules <リポジトリの git リンク> -b dev - ``` + ```bash + git clone --recurse-submodules <リポジトリの git リンク> -b dev + ``` - ::: warning - Visual Studio など `--recurse-submodules` パラメータに対応していない Git GUI を使用する場合、クローン後に以下を実行: + ::: warning + Visual Studio など `--recurse-submodules` パラメータに対応していない Git GUI を使用する場合、クローン後に以下を実行: - ```bash - git submodule update --init - ``` + ```bash + git submodule update --init + ``` - ::: + ::: 4. 事前ビルド済みサードパーティライブラリのダウンロード - **Python環境が必要(インストール方法は各自検索)** - _(tools/maadeps-download.py はプロジェクトルートに配置)_ + **Python環境が必要(インストール方法は各自検索)** + _(tools/maadeps-download.py はプロジェクトルートに配置)_ - ```cmd - python tools/maadeps-download.py - ``` + ```cmd + python tools/maadeps-download.py + ``` 5. 開発環境の設定 - - - `Visual Studio 2022 Community` をインストール時、`C++ によるデスクトップ開発` と `.NET デスクトップ開発` を選択必須 + - `Visual Studio 2022 Community` をインストール時、`C++ によるデスクトップ開発` と `.NET デスクトップ開発` を選択必須 6. `MAA.sln` をダブルクリックで開き、Visual Studio にプロジェクトを自動ロード 7. VS の設定 - - - 上部設定バーで `RelWithDebInfo` `x64` を選択(Release ビルド/ARM プラットフォームの場合は不要) - - `MaaWpfGui` 右クリック → プロパティ → デバッグ → ネイティブデバッグを有効化(C++ Core へのブレークポイント設定可能) + - 上部設定バーで `RelWithDebInfo` `x64` を選択(Release ビルド/ARM プラットフォームの場合は不要) + - `MaaWpfGui` 右クリック → プロパティ → デバッグ → ネイティブデバッグを有効化(C++ Core へのブレークポイント設定可能) 8. これで自由に ~~改造~~ 開発を始められます 9. 一定量の変更ごにコミット(メッセージ記入必須) Git 未経験者は dev ブランチ直接変更ではなく新規ブランチ作成推奨: - ```bash - git branch your_own_branch - git checkout your_own_branch - ``` + ```bash + git branch your_own_branch + git checkout your_own_branch + ``` - これで dev の更新影響を受けずに開発可能 + これで dev の更新影響を受けずに開発可能 10. 開発完了後、変更をリモートリポジトリへプッシュ: @@ -68,30 +66,29 @@ icon: iconoir:developer 11. [MAA メインリポジトリ](https://github.com/MaaAssistantArknights/MaaAssistantArknights) で Pull Request を提出(master ではなく dev ブランチを指定) 12. 上流リポジトリの更新を同期する場合: - 1. 上流リポジトリを追加: - ```bash - git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git - ``` + ```bash + git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git + ``` 2. 更新を取得: - ```bash - git fetch upstream - ``` + ```bash + git fetch upstream + ``` 3. リベース(推奨)またはマージ: - ```bash - git rebase upstream/dev - ``` + ```bash + git rebase upstream/dev + ``` - または + または - ```bash - git merge - ``` + ```bash + git merge + ``` 4. ステップ7、8、9、10 を繰り返し @@ -103,9 +100,9 @@ Visual Studio 起動後、Git 操作は「Git 変更」画面からコマンド 1. clang-format バージョン20.1.0以上をインストールします。 - ```bash - python -m pip install clang-format - ``` + ```bash + python -m pip install clang-format + ``` 2. 'Everything'などのツールを使用して、clang-format.exeのインストール場所を見つけます。参考までに、Anacondaを使用している場合、clang-format.exeはYourAnacondaPath/Scripts/clang-format.exeにインストールされます。 3. Visual Studioで、 Tools-Optionsで 'clang-format'を検索します。 @@ -125,6 +122,4 @@ Visual Studio 起動後、Git 操作は「Git 変更」画面からコマンド GitHub codespace を作成して C++ 開発環境を自動的に構成する -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights) - -次に、 vscode または [Linuxチュートリアル](./linux-tutorial.md) のプロンプトに従って、 GCC 12 および CMake プロジェクトを構成します。 +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights?devcontainer_path=.devcontainer%2F1%2Fdevcontainer.json) diff --git a/docs/ja-jp/develop/linux-tutorial.md b/docs/ja-jp/develop/linux-tutorial.md index 8c3885986f..d535fc2b9a 100644 --- a/docs/ja-jp/develop/linux-tutorial.md +++ b/docs/ja-jp/develop/linux-tutorial.md @@ -14,7 +14,6 @@ MAAの構築方法はまだ議論されていますが、このチュートリ ## コンパイルプロセス 1. コンパイルに必要な依存をダウンロードして - - Ubuntu/Debian ```bash @@ -24,7 +23,6 @@ MAAの構築方法はまだ議論されていますが、このチュートリ 2. サードパーティ製ライブラリのコンパイル 構築済みの依存ライブラリをダウンロードするか、最初からコンパイルするかを選択できます - - 事前構築されたサードパーティ製ライブラリのダウンロード(推奨) > **Note** @@ -35,7 +33,6 @@ MAAの構築方法はまだ議論されていますが、このチュートリ ``` 上記の方法でダウンロードしたライブラリがABIバージョンなどの理由でシステム上で実行できず、コンテナなどのスキームを使用したくないことがわかった場合は、最初からコンパイルしてみることもできます - - サードパーティ製ライブラリを直接にコンパイルする(時間がかかる) ```bash diff --git a/docs/ja-jp/develop/overseas-client-adaptation.md b/docs/ja-jp/develop/overseas-client-adaptation.md index 29739ef0ef..04b7291711 100644 --- a/docs/ja-jp/develop/overseas-client-adaptation.md +++ b/docs/ja-jp/develop/overseas-client-adaptation.md @@ -43,7 +43,7 @@ icon: ri:earth-fill 例えば、切り取られた後の出力は次のようになる。 -``` log +```log src: Screenshot_xxx.png dst: Screenshot_xxx.png_426,272,177,201.png original roi: 476, 322, 77, 101, @@ -60,8 +60,8 @@ amplified roi: 426, 272, 177, 201 例 -- ENクライアントのテンプレートイメージフォルダの場所は `MaaAssistantArknights\resource\global\YoStarEN\resource\template`. -- 大陸版クライアントのテンプレートイメージフォルダの場所は `MaaAssistantArknights\resource\template`. +- ENクライアントのテンプレートイメージフォルダの場所は `MaaAssistantArknights\resource\global\YoStarEN\resource\template`. +- 大陸版クライアントのテンプレートイメージフォルダの場所は `MaaAssistantArknights\resource\template`. task.json`ファイルに記載されているテンプレート画像を参照し、大陸版クライアントと海外クライアントのテンプレート画像を比較し、海外クライアントに不足しているテンプレートを特定します。 @@ -75,8 +75,8 @@ task.json`ファイルに記載されているテンプレート画像を参照 例 -- ENクライアントの `task.json` の場所は `MaaAssistantArknights\resource\global\YoStarEN\resource\tasks.json`. -- 大陸版クライアントの `task.json` の場所は `MaaAssistantArknights\resource\tasks.json`. +- ENクライアントの `task.json` の場所は `MaaAssistantArknights\resource\global\YoStarEN\resource\tasks.json`. +- 大陸版クライアントの `task.json` の場所は `MaaAssistantArknights\resource\tasks.json`. テキストを変更するには、対応するタスクを探し、`text`フィールドを対応するサーバーに表示されている内容に変更します。特定された内容は、ゲーム内の完全な内容の部分文字列である可能性があることに留意してください。一般的には、純粋なASCII文字として認識されない限り、テキストを含む`text`はすべて置き換える必要があります。 @@ -108,7 +108,7 @@ ROIの範囲を変更するには ログを解析することは、プログラムに関する問題を特定するのに役立ちます。以下はログの例 -``` 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.541][TRC][Px7ec][Tx15c8] OcrPack::recognize | roi: [ 500, 50, 300, 150 ] @@ -130,6 +130,7 @@ ROIの範囲を変更するには - `"taskid"` はタスク番号です。 - `"class"` と `subtask` はそれぞれ、タスクのクラスとサブタスクを表す。 - `"pre_task"` は一つ前のタスクを表す。 + さらに、コマンドの実行結果 (例: `Call`) と `OCR` の情報 (例: `OcrPack::recognize`) がログに記録されます。 例えば、このログの `"to_be_recognized"`,`"cur_retry":3, "retry_times":20` は、タスクの認識を10回試行し、最大回数は20回であることを意味しています。最大回数に達すると、そのタスクはスキップされ、エラーが報告され、次のタスクが実行されます。前のタスクで問題がない場合、ここで認識に問題がある可能性があります。この問題をトラブルシューティングするには、ログに記載されているタスクに対応するテンプレートファイルがあるか、対応するタスクの `text` フィールドが正しくないか、タスク認識のための `roi` 範囲が正しくないかを確認し、必要な修正を加えてください。 diff --git a/docs/ja-jp/develop/pr-tutorial.md b/docs/ja-jp/develop/pr-tutorial.md index a74f0e7834..3c2fdb25f6 100644 --- a/docs/ja-jp/develop/pr-tutorial.md +++ b/docs/ja-jp/develop/pr-tutorial.md @@ -5,7 +5,7 @@ icon: mingcute:git-pull-request-fill # 純WebサイトのPRチュートリアル -「パラスちゃん」も理解できるGitHubのPull Requestの使用ガイド (*´▽`)ノノ +「パラスちゃん」も理解できるGitHubのPull Requestの使用ガイド (\*´▽`)ノノ この文書は機械翻訳です。もし可能であれば、中国語の文書を読んでください。もし誤りや修正の提案があれば、大変ありがたく思います。 @@ -75,79 +75,79 @@ Conflictを解決するのは少し面倒ですが、ここでは概念につい 1. まず、MAAのメインリポジトリにアクセスして、コードをforkします。 - + 2. 「Copy the master branch only」オプションを外して、Create Forkをクリックします。 - + 3. 次に、あなたの個人リポジトリに移動し、「あなたの名前/ MaaAssistantArknights」というタイトルが表示され、下に「MAAメインリポジトリから複製されたMaaAssistantArknights/MaaAssistantArknights」という文言が表示されます。 - + 4. 変更するファイルを探します。 "Go to file" をクリックしてグローバル検索を行うか、下のフォルダーから直接検索することもできます(ファイルの場所を知っている場合)。 - + 5. ファイルを開いたら、ファイルの右上隅にある✏️をクリックして編集を開始します。 - + 6. 変更を加えます!(もちろん、リソースファイルなどの場合は、まずMAAフォルダー内で変更をテストし、問題がないことを確認してから、ウェブページに貼り付けて変更を行ってください) 7. 変更が完了したら、一番下までスクロールして、変更内容を記述します。 - + - + 8. 変更するもう1つのファイルがある場合は、5-8を繰り返してください。 9. 変更が完了したら、PRを行います!個人リポジトリのPull Requestタブをクリックします。 - 「Compare & Pull Request」ボタンがある場合は、それをクリックしてください。ない場合は、「New Pull Request」をクリックしてください。 + 「Compare & Pull Request」ボタンがある場合は、それをクリックしてください。ない場合は、「New Pull Request」をクリックしてください。 - + 10. これでメインリポジトリに移動します。PRする内容を確認してください。 - スクリーンショットのように、真ん中に左向きの矢印があり、右側の「個人名/MAA」のdevブランチを「メインリポジトリ/MAA」のdevブランチにマージすることを申請しています。 + スクリーンショットのように、真ん中に左向きの矢印があり、右側の「個人名/MAA」のdevブランチを「メインリポジトリ/MAA」のdevブランチにマージすることを申請しています。 11. MAAチームの大佬たちに承認していただきましょう!もちろん、意見を提供してくださることもあるかもしれません - 👇例えば(純粋に娯楽のために、本気にしないでください) + 👇例えば(純粋に娯楽のために、本気にしないでください) + { + light: 'images/zh-cn/pr-tutorial/pr-11-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-11-dark.png' + } + ]" /> 12. 大佬たちがさらに小さな問題を修正するように言った場合、あなたの個人のリポジトリに戻って、以前のdevブランチに切り替え、手順3-9を繰り返すだけで大丈夫です! - 手順2(再度フォークする)を実行する必要はなく、手順10(再度プルリクエストする)を実行する必要もありません。現在のプルリクエストはまだ承認待ちの状態にあり、後続の変更はこのプルリクエストに直接反映されます。 - 👇 以下は例です。最下部に「再度変更デモを変更」というメッセージが追加されたことがわかります。 + 手順2(再度フォークする)を実行する必要はなく、手順10(再度プルリクエストする)を実行する必要もありません。現在のプルリクエストはまだ承認待ちの状態にあり、後続の変更はこのプルリクエストに直接反映されます。 + 👇 以下は例です。最下部に「再度変更デモを変更」というメッセージが追加されたことがわかります。 + { + light: 'images/zh-cn/pr-tutorial/pr-12-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-12-dark.png' + } + ]" /> 13. 大佬たちの承認を得たら、すべて完了です! バージョンがリリースされた後、あなたのGitHubプロフィールアイコンは自動的に貢献者リストに追加されます。皆様のご奉仕に深く感謝申し上げます! ~~なんで全部二次元キャラなんだろう、あ、私も二次元好きだったわ。ま、いいか~~ @@ -194,7 +194,7 @@ Conflictを解決するのは少し面倒ですが、ここでは概念につい [![Contributors](https://contributors-img.web.app/image?repo=MaaAssistantArknights/MaaAssistantArknights&max=105&columns=15)](https://github.com/MaaAssistantArknights/MaaAssistantArknights/graphs/contributors) ::: -14. 次回別のPRを提出する場合は、まずdevブランチに切り替えて、以下の図のように直接操作してください。 +14. 次回別のPRを提出する場合は、まずdevブランチに切り替えて、以下の図のように直接操作してください。 ::: warning この操作は、あなたの個人リポジトリをメインリポジトリとまったく同じ状態に強制的に同期するものであり、最も簡単で効果的な競合解消方法です。ただし、あなたの個人リポジトリにすでに追加されているものは削除されます! diff --git a/docs/ja-jp/develop/vsc-ext-tutorial.md b/docs/ja-jp/develop/vsc-ext-tutorial.md index f65d3aab57..a0bdeac5ea 100644 --- a/docs/ja-jp/develop/vsc-ext-tutorial.md +++ b/docs/ja-jp/develop/vsc-ext-tutorial.md @@ -5,8 +5,8 @@ icon: iconoir:code-brackets # Dedicated VSCode Extension Tutorial -* [Extension Store](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) -* [Repository](https://github.com/neko-para/maa-support-extension) +- [Extension Store](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) +- [Repository](https://github.com/neko-para/maa-support-extension) ## Installation @@ -60,10 +60,10 @@ When enabling the `Maa` compatible mode, the extension will be able to recursive The extension supports scheduled scanning and diagnosing all tasks. -* Check if contains task defs with same names. -* Check if contains unknown task refs. -* Check if contains unknown image refs. -* Check if contains duplicated task refs in a single task. +- Check if contains task defs with same names. +- Check if contains unknown task refs. +- Check if contains unknown image refs. +- Check if contains duplicated task refs in a single task. #### Multiple paths resource support @@ -83,11 +83,11 @@ Searching and launching `Maa: open crop tool` inside VSCode command panel can op > Use `Ctrl+Shift+P` (`Command+Shift+P` on MacOS) to open command panel -* After selecting and connecting to the controller, use `Screencap` button to obtain screenshots -* Use `Upload` button to manually upload images. -* Hold `Ctrl` key and select cropping area -* Use wheels to zoom -* After finishing cropping, use `Download` button to save the cropping result to the folder of the topest layer of the activated resource +- After selecting and connecting to the controller, use `Screencap` button to obtain screenshots +- Use `Upload` button to manually upload images. +- Hold `Ctrl` key and select cropping area +- Use wheels to zoom +- After finishing cropping, use `Download` button to save the cropping result to the folder of the topest layer of the activated resource ### Bottom status bar diff --git a/docs/ja-jp/manual/connection.md b/docs/ja-jp/manual/connection.md index a3d97353a7..d276b0838e 100644 --- a/docs/ja-jp/manual/connection.md +++ b/docs/ja-jp/manual/connection.md @@ -55,7 +55,6 @@ icon: mdi:plug ::: details 代替案 - オプション 1 : ADB コマンドを使用してエミュレータのポートを確認します - 1. **単一**のエミュレータを起動し、他に Android デバイスがこのコンピュータに接続されていないことを確認します。 2. ADB 実行可能ファイルが格納されているフォルダでターミナルを起動します。 3. 次のコマンドを実行します。 @@ -78,7 +77,6 @@ icon: mdi:plug 使用 `127.0.0.1:<ポート>` または `emulator-<四桁の数字>` を接続アドレスとして使用します。 - 方法2:すでに確立されたADB接続を検索する - 1. 方法1を実行します。 2. `Windowsキー+S` を押して検索バーを開き、「リソースモニター」を入力して開きます。 3. `ネットワーク` タブに切り替えて、モニターするポート名であるシミュレータープロセス名(例:`HD-Player.exe`)を検索します。 @@ -175,7 +173,6 @@ MAA は現在 `bluestacks.conf` の保存場所をレジストリから読み取 ::: 1. ブルースタックスシミュレータのデータディレクトリ内にある `bluestacks.conf` ファイルを見つけます。 - - 国際版のデフォルトパスは `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` です。 - 中国本土版のデフォルトパスは `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` です。 diff --git a/docs/ja-jp/manual/device/android.md b/docs/ja-jp/manual/device/android.md index be7a9b1814..06724cb6ce 100644 --- a/docs/ja-jp/manual/device/android.md +++ b/docs/ja-jp/manual/device/android.md @@ -11,11 +11,12 @@ icon: mingcute:android-fill ::: info 注意 -1. Android 10 以降、SELinux が `Enforcing` モードの場合、Minitouch は使用できません、別のタッチモードに切り替えてください。または SELinux を **一時的に** `Permissive` モードに切り替え。 +1. Android 10 以降、SELinux が `Enforcing` モードの場合、Minitouch は使用できません、別のタッチモードに切り替えてください。または SELinux を **一時的に** `Permissive` モードに切り替え。 2. Androidエコシステムは複雑なため、モードが正常に使用できるようになるまで、MAAの `設定` - `接続設定` で `接続構成` を `一般モード` 、 `互換モード` 、 `2番目の決議` または `一般モード(ブロックされた例外出力)`に変更してみてください。 3. MAAは `16:9` 比率の `720p` 以上の解像度にしか対応していません、ほとんどの近代的なデバイスを含む、`16:9` または `9:16` の画面比率でないデバイスは解像度を強制的に変更する必要があります。接続されているデバイスの画面解像度の比率がネイティブで `16:9` または `9:16`,の場合は、`解像度の変更` セクションをスキップできます。 4. 誤操作を避けるため、デバイスのナビゲーションモードを `クラシックナビゲーションキー` など、 `フルスクリーンジェスチャー` 以外の方法に切り替えてください。 5. エラーを避けるため、ゲーム内設定の `異形スクリーンUI対応` 項目を0に調整してください。 + ::: ::: tip @@ -35,7 +36,6 @@ icon: mingcute:android-fill ``` - 実行に成功すると `USB デバッグ` デバイスが接続されたというメッセージが表示される。 - - 成功した接続例: ```bash @@ -102,7 +102,7 @@ icon: mingcute:android-fill :: 解像度を 1080p に調整する adb -s <ターゲット・デバイスのシリアル番号> shell wm size 1080x1920 :: 画面の輝度を下げる(オプション) - adb -s <ターゲット・デバイスのシリアル番号> shell settings put system screen_brightness 1 + adb -s <ターゲット・デバイスのシリアル番号> shell settings put system screen_brightness 1 ``` ```bash @@ -114,10 +114,9 @@ icon: mingcute:android-fill adb -s <ターゲット・デバイスのシリアル番号> shell input keyevent 3 :: ロック画面(オプション) adb -s <ターゲット・デバイスのシリアル番号> shell input keyevent 26 - ``` + ``` 2. 最初のファイルを `startup.bat` に、2番目のファイルを `finish.bat` にリネームする。 - - リネーム後、拡張子を変更するための2回目の確認ダイアログボックスが表示されず、ファイルアイコンも変更されない場合は、“Windowsでファイルの拡張子を表示する方法“をご自身で検索してください。 3. MAA の `設定` - `接続設定` - `スクリプトを使用して始めます` と `終了時にスクリプトを使用します` にそれぞれ `startup.bat` と `finish.bat` を記入してください。 @@ -148,7 +147,6 @@ icon: mingcute:android-fill ``` 2. デバイスのIPアドレスを表示します。 - - デバイスの `設定` - `WLAN` を開き、現在接続されているワイヤレスネットワークをタップしてIPアドレスを表示します。 - セッティング位置は各機器ブランドによって異なるので、各自で確認してほしい。 @@ -164,7 +162,6 @@ icon: mingcute:android-fill 1. デバイスの開発者向けオプションに移動し、 `ワイヤレスデバッグ` をクリックしてオンにし、OKをクリックして、 `ペアリングコードでデバイスをペアリング` をクリックして、ペアリングが完了するまで表示されるポップアップウィンドウを閉じないでください。 2. ペアリングします。 - 1. コマンドプロンプトウィンドウに `adb pair <デバイスのポップアップで指定されたIPアドレスとポート>` 、Enter キーを押します。 2. `<デバイスのポップアップウィンドウに表示される6桁のペアリングコード>` と入力し、Enter キーを押します。 3. ウィンドウに `Successfully paired to ` と表示され、デバイスのポップアップウィンドウが自動的に消え、ペアリングされたデバイスの下部にコンピューター名が表示されます。 diff --git a/docs/ja-jp/manual/device/linux.md b/docs/ja-jp/manual/device/linux.md index 41e81798cb..5fb06d1334 100644 --- a/docs/ja-jp/manual/device/linux.md +++ b/docs/ja-jp/manual/device/linux.md @@ -25,7 +25,6 @@ icon: teenyicons:linux-alt-solid 1. [`if asst.connect('adb.exe', '127.0.0.1:5554'):`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/722f0ddd4765715199a5dc90ea1bec2940322344/src/Python/sample.py#L48) セクションを見つける 2. `adb` ツール呼び出し - - エミュレータが `Android Studio` に `avd` を使用している場合は、 `adb` が付属します。 `adb.exe` の欄に直接 `adb` パスを記入することができ、一般的には `$HOME/Android/Sdk/platform-tools/` で見つけることができます。例: ```python @@ -35,7 +34,6 @@ icon: teenyicons:linux-alt-solid - 他のエミュレータを使用する場合は、最初に `adb` をダウンロードして: `$ sudo apt install adb` 次に、パスを入力するか、 `PATH` 環境変数を使用して `adb` を直接入力します 3. エミュレータの `adb` パス取得 - - adb ツールを直接使用できます: `$ adbパス devices` ,例: ```shell diff --git a/docs/ja-jp/manual/faq.md b/docs/ja-jp/manual/faq.md index 11ccb94cd4..936ededaa4 100644 --- a/docs/ja-jp/manual/faq.md +++ b/docs/ja-jp/manual/faq.md @@ -57,8 +57,8 @@ Windows 7 の場合、上記の 2 つのランタイムライブラリをイン 1. [Windows 7 Service Pack 1](https://support.microsoft.com/ja-jp/windows/windows-7-service-pack-1-sp1-%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B-b3da2c0f-cdb6-0572-8596-bab972897f61) 2. SHA-2 コード署名: - - KB4474419:[ダウンロードリンク1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)、[ダウンロードリンク2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu) - - KB4490628:[ダウンロードリンク1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)、[ダウンロードリンク2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu) + - KB4474419:[ダウンロードリンク1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)、[ダウンロードリンク2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu) + - KB4490628:[ダウンロードリンク1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)、[ダウンロードリンク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):[ダウンロードリンク1](https://catalog.s.download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu)、[ダウンロードリンク2](http://download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu) ##### .NET 8 アプリケーションが Windows 7 で異常に動作する場合の緩和策 [#8238](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/8238) @@ -97,6 +97,7 @@ Windows 7 で .NET 8 アプリケーションを実行すると、メモリ使 - エミュレータのインストールパスを見つける。Windowsはエミュレータの実行中にタスクマネージャーでプロセスを右クリックし、 `ファイルの場所を開く` をクリックします。 - トップまたはボトムのディレクトリに高確率で `adb.exe` が存在する可能性があります(必ずしもこの名前で呼ばれているとは限りません。`nox_adb.exe`、`HD-adb.exe`、`adb_server.exe` などと呼ばれる場合があります。とにかく名前に `adb` が含まれるexeです) 。それを選択してください。 + ::: - 接続アドレスが正しく入力されていることを確認してください。使用しているエミュレータのadbアドレスをインターネットで検索できます。通常は `127.0.0.1:5555` のような形式です(LDPlayerを除く)。 @@ -179,9 +180,8 @@ MAA はレジストリから `bluestacks.conf` の保存場所を読み取ろう ::: 1. Bluestacksエミュレータのデータディレクトリにある`bluestacks.conf`ファイルを探します - - - グローバル版のデフォルトパス `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` - - 中国版のデフォルトパス `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` + - グローバル版のデフォルトパス `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` + - 中国版のデフォルトパス `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` 2. 初めて MAA を使用する場合は、一度 MAA を起動してください。MAAの `config` ディレクトリに `gui.json` が生成されます。 diff --git a/docs/ja-jp/manual/introduction/combat.md b/docs/ja-jp/manual/introduction/combat.md index 7dca3b2231..0b92e90db6 100644 --- a/docs/ja-jp/manual/introduction/combat.md +++ b/docs/ja-jp/manual/introduction/combat.md @@ -8,7 +8,6 @@ icon: hugeicons:brain-02 ## 一般設定 - `理性剤使用数` と `割る源石の数`、および `周回数指定`・`素材の指定` はいずれもショートサーキット的なスイッチ(OR条件)です。これら3つの条件のうちいずれかを満たした時点でタスク達成とみなし、作戦を停止します。 - - `理性剤使用数` は理性を何回分補充するかを指定します(1回で複数本使う場合あり)。 - `割る源石の数` は源石を何個割るかを指定します(1回につき1個)。倉庫に理性剤がある場合は源石を割りません。 - `周回数指定` は選択したステージを何回周回するかを指定します(例:「15回周回後に停止」)。 @@ -19,19 +18,19 @@ icon: hugeicons:brain-02 ::: details 例 -| 理性剤使用数 | 割る源石の数 | 周回数指定 | 素材の指定→ドロップ数 | 結果 | -| :------: | :----: | :------: | :------: | -------------------------------------------------------------------------------------------------------------------------------------- | -| | | | | 所持理性を消費し切ったら終了。 | -| 2 | | | | まず所持理性を使い切り、その後理性剤を1回使用。合計 `2` 回分の補充後、理性を使い切って終了。 | -| _999_ | 2 | | | まず所持理性を使い切り、理性剤を使い切ってから源石を割る。源石は合計 `2` 回。理性を使い切って終了。 | -| | | 2 | | 選択ステージを `2` 回周回して終了。 | -| | | | 2 | ドロップ統計で指定素材を `2` 個入手した時点で終了。 | -| 2 | | 4 | | 最大 `2` 回まで理性剤を使用する前提で、選択ステージを `4` 回周回して終了。 | -| 2 | | | 4 | 最大 `2` 回まで理性剤を使用する前提で、ドロップ統計で指定素材を `4` 個入手したら終了。 | -| 2 | | 4 | 8 | 最大 `2` 回まで理性剤を使用する前提で、`4` 回周回したら終了。ただし `4` 回に到達する前に指定素材を `8` 個入手した場合は前倒しで終了。 | -| _999_ | 4 | 8 | 16 | 理性剤を使い切り、さらに源石を `4` 回割る前提で、`8` 回周回したら終了。ただし `8` 回に到達する前に指定素材を `16` 個入手した場合は前倒しで終了。 | -| | 2 | | | まず所持理性を使い切る。倉庫に理性剤があればそこで終了。理性剤がなければ源石を `2` 回割り、理性を使い切って終了。_MAA GUIの動作ではありません_ | -| 2 | 4 | | | まず所持理性を使い切る。`2` 回分の理性剤を使い終えても理性剤が残っていれば終了。`2` 回以内で理性剤が尽きた場合は源石を `4` 回割り、理性を使い切って終了。_MAA GUIの動作ではありません_ | +| 理性剤使用数 | 割る源石の数 | 周回数指定 | 素材の指定→ドロップ数 | 結果 | +| :----------: | :----------: | :--------: | :-------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| | | | | 所持理性を消費し切ったら終了。 | +| 2 | | | | まず所持理性を使い切り、その後理性剤を1回使用。合計 `2` 回分の補充後、理性を使い切って終了。 | +| _999_ | 2 | | | まず所持理性を使い切り、理性剤を使い切ってから源石を割る。源石は合計 `2` 回。理性を使い切って終了。 | +| | | 2 | | 選択ステージを `2` 回周回して終了。 | +| | | | 2 | ドロップ統計で指定素材を `2` 個入手した時点で終了。 | +| 2 | | 4 | | 最大 `2` 回まで理性剤を使用する前提で、選択ステージを `4` 回周回して終了。 | +| 2 | | | 4 | 最大 `2` 回まで理性剤を使用する前提で、ドロップ統計で指定素材を `4` 個入手したら終了。 | +| 2 | | 4 | 8 | 最大 `2` 回まで理性剤を使用する前提で、`4` 回周回したら終了。ただし `4` 回に到達する前に指定素材を `8` 個入手した場合は前倒しで終了。 | +| _999_ | 4 | 8 | 16 | 理性剤を使い切り、さらに源石を `4` 回割る前提で、`8` 回周回したら終了。ただし `8` 回に到達する前に指定素材を `16` 個入手した場合は前倒しで終了。 | +| | 2 | | | まず所持理性を使い切る。倉庫に理性剤があればそこで終了。理性剤がなければ源石を `2` 回割り、理性を使い切って終了。_MAA GUIの動作ではありません_ | +| 2 | 4 | | | まず所持理性を使い切る。`2` 回分の理性剤を使い終えても理性剤が残っていれば終了。`2` 回以内で理性剤が尽きた場合は源石を `4` 回割り、理性を使い切って終了。_MAA GUIの動作ではありません_ | ::: @@ -46,7 +45,6 @@ icon: hugeicons:brain-02 - アーツ学・購買資格証・炭素材の第 5 ステージ。`CA-5` / `AP-5` / `SK-5` を入力してください。 - すべてのSoCステージ。`PR-A-1` のように完全な番号を入力してください。 - 殲滅作戦は以下の入力値に対応し、対応する Value を使用してください: - - 当期殲滅作戦:Annihilation - チェルノボーグ:Chernobog@Annihilation - 龍門郊外:LungmenOutskirts@Annihilation diff --git a/docs/ja-jp/manual/introduction/integrated-strategy.md b/docs/ja-jp/manual/introduction/integrated-strategy.md index 960976e858..8c7b738577 100644 --- a/docs/ja-jp/manual/introduction/integrated-strategy.md +++ b/docs/ja-jp/manual/introduction/integrated-strategy.md @@ -37,13 +37,13 @@ MAAはデフォルトで最新のテーマを選択しますが、`自動ロゲ 難易度の推奨は、`敵の難易度`、`希望消費`、`スコア倍率`などの要素を総合的に考慮しています。高い練度でテストした場合、比較的安定しており、実際の状況やニーズに応じて自由に調整できます。 -| テーマ | 備考 | -| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ファントム | `正式調査·3` およびそれ以上の難易度で開始すると、希望消費を減少させるアイテムが手に入る場合があり、そのため開始時に六星オペレーターを召集できないことがあります。 | -| ミヅキ | `波瀾万丈·4` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `精神論分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。
`精神論分隊` はアカウントの練度が高い場合に適しており、運に頼る必要があります。 | -| サーミ | `自然の猛威·6` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `特訓分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。 | -| サルカズ | `魂に直面·15` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `歴史再編`内でまだ `位置測定分隊強化Ⅱ`を有効にしていない場合、 `位置測定分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。
`位置測定分隊`を選択した場合、回避戦略が採用され、 `魂のしおり`を素早く取得できますが、基本的にエンディングをクリアすることはできません。
源石錐を収集戦略を使用した場合、開始時の分隊は `破棘成金分隊` とならば、商店更新戦略を使用してプロセスを加速します。 | -| 界園 | `請君入園·15` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `指揮分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。
難易度が `請君入園·3`に設定され、源石錐を収集戦略を使用して開始時の分隊が `指揮分隊` とならば、 `時の果て` でスキップ戦略を使用してプロセスを加速します。 | +| テーマ | 備考 | +| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ファントム | `正式調査·3` およびそれ以上の難易度で開始すると、希望消費を減少させるアイテムが手に入る場合があり、そのため開始時に六星オペレーターを召集できないことがあります。 | +| ミヅキ | `波瀾万丈·4` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `精神論分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。
`精神論分隊` はアカウントの練度が高い場合に適しており、運に頼る必要があります。 | +| サーミ | `自然の猛威·6` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `特訓分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。 | +| サルカズ | `魂に直面·15` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `歴史再編`内でまだ `位置測定分隊強化Ⅱ`を有効にしていない場合、 `位置測定分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。
`位置測定分隊`を選択した場合、回避戦略が採用され、 `魂のしおり`を素早く取得できますが、基本的にエンディングをクリアすることはできません。
源石錐を収集戦略を使用した場合、開始時の分隊は `破棘成金分隊` とならば、商店更新戦略を使用してプロセスを加速します。 | +| 界園 | `請君入園·15` およびそれ以上の難易度では、六星オペレーターの召集に必要な希望消費が+1されます。 `指揮分隊` を使用して開始した場合、六星オペレーターを召集できないことがあります。
難易度が `請君入園·3`に設定され、源石錐を収集戦略を使用して開始時の分隊が `指揮分隊` とならば、 `時の果て` でスキップ戦略を使用してプロセスを加速します。 | ::: diff --git a/docs/ja-jp/manual/introduction/introduction_old.md b/docs/ja-jp/manual/introduction/introduction_old.md index 150a418350..53ba8dd06b 100644 --- a/docs/ja-jp/manual/introduction/introduction_old.md +++ b/docs/ja-jp/manual/introduction/introduction_old.md @@ -32,12 +32,12 @@ icon: ic:baseline-article - `周回数指定` ステージを何回周回するか指定(例“15 周 で停止”) - `素材を限定` 特定の素材のドロップ数が手に入るまで周回(例“5 個 初級源岩獲得で停止”) -| 例 | 理性剤使用数 | 割る源石の数 | 周回数指定 | 素材を限定 | 結果 | -|:--:|:--------:|:------:|:--------:|:---------:|-----------------------------------------------------------------------------------------------------------------------------------------------| -| A | 999 | 10 | 1 | ✖ | 理性材/純正源石を**1回**以上摂取し、`周回数:1`回の条件を完了すると、即座に停止。理性不足の状態で純正源石か理性剤が不足している場合は摂取せずに自動的に終了します。 | -| B | ✖ | ✖ | 100 | ✖ | 100回ステージを実行しようとしますが、現在使用可能な理性を消費後(おそらく数回)に、`理性剤`、`純正源石`なしの条件が達成されるため、理性を消費できず、タスクは完了されます。 | -| C | 1 | ✖ | 100 | ✖ | 100回ステージを実行しようとしますが、理性剤を 1 個消費した後に理性が不足した場合、`理性剤使用数:1`、`割る源石の数0`の条件を達成したためタスクは完了します。 | -| D | 999 | ✖ | 100 | 3個初級源岩 | 100回ステージを実行しようとし、最大 999 の理性剤を消費しようとしますが、実行中に3個の初級源岩を獲得した場合、`素材を限定:3個の初級源岩`の条件を達成するため、その時点でタスクを完了し停止します。 | +| 例 | 理性剤使用数 | 割る源石の数 | 周回数指定 | 素材を限定 | 結果 | +| :-: | :----------: | :----------: | :--------: | :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A | 999 | 10 | 1 | ✖ | 理性材/純正源石を**1回**以上摂取し、`周回数:1`回の条件を完了すると、即座に停止。理性不足の状態で純正源石か理性剤が不足している場合は摂取せずに自動的に終了します。 | +| B | ✖ | ✖ | 100 | ✖ | 100回ステージを実行しようとしますが、現在使用可能な理性を消費後(おそらく数回)に、`理性剤`、`純正源石`なしの条件が達成されるため、理性を消費できず、タスクは完了されます。 | +| C | 1 | ✖ | 100 | ✖ | 100回ステージを実行しようとしますが、理性剤を 1 個消費した後に理性が不足した場合、`理性剤使用数:1`、`割る源石の数0`の条件を達成したためタスクは完了します。 | +| D | 999 | ✖ | 100 | 3個初級源岩 | 100回ステージを実行しようとし、最大 999 の理性剤を消費しようとしますが、実行中に3個の初級源岩を獲得した場合、`素材を限定:3個の初級源岩`の条件を達成するため、その時点でタスクを完了し停止します。 | - `素材を限定` と `ステージ選択` は2つの別々のロジックです。 - `素材を限定` は、タスクを完了するための素材の数に基づいており、対応するステージに自動的に移動しません。 @@ -121,7 +121,7 @@ icon: ic:baseline-article ### 自動戦闘(現在JP未対応) - 適応していないことが示されていますが、自動攻略ファイル内の中国語の指示を理解できる限り、ほとんどの機能を使用できます。アプリがバグで立ち往生した場合は、Issueを提出してフィードバックをお寄せください。 -- 自動攻略ファイルのシェアは大歓迎です! +- 自動攻略ファイルのシェアは大歓迎です! - [prts.plus](https://prts.plus) をご利用ください! #### 使い方 @@ -129,9 +129,9 @@ icon: ic:baseline-article `編成可能のステージ` と `保全駐在` モードでの自動戦闘をサポートします。 - この機能は、`行動開始` のある画面で開始する必要があります。 -その後、 `攻略ファイルパス` または `ミステリーコード` をMAAの左上にあるボックスに入力するで、ジョブをインポートできます。 + その後、 `攻略ファイルパス` または `ミステリーコード` をMAAの左上にあるボックスに入力するで、ジョブをインポートできます。 - さらに、ビデオ認識がサポートされており(テスト中)、ビデオファイルをドラッグすることでアクティブ化できます。 - アスペクト比16:9、解像度720p以上の動画にのみ対応しています。動画には、黒枠、歪み補正、エミュレータの枠などが含まれていないことが必須です。 + アスペクト比16:9、解像度720p以上の動画にのみ対応しています。動画には、黒枠、歪み補正、エミュレータの枠などが含まれていないことが必須です。 - `自動編成` 機能は、**現在の編成をクリアし**、ジョブに必要なオペレーターに基づいて編成を自動的に完了します。 - `自動編成` は、必要に応じてキャンセルして(たとえば、必要に応じて `戦友サポート` を使用する場合)、手動編成後に開始する。 - `カスタムオペレーターを追加する` と `信頼性の低いオペレーターを追加する` は、ミッションの必要に応じて自動編成に追加できます。 @@ -140,7 +140,7 @@ icon: ic:baseline-article - 自動戦闘の「サイクル数」を設定できます(例:保全駐在)。 - `バトルリスト` 機能を使用して、同じエリア内のステージの連続した自動戦闘をキューに入れることができます。 - ジョブをインポートしたら、以下のリストのステージコードが正しいことを確認してから、ステージを追加します(代わりに右クリックして強襲作戦を追加します)。 - 追加後、対応するステージの作戦を行うかどうかのオンとオフを切り替えることができます。 + 追加後、対応するステージの作戦を行うかどうかのオンとオフを切り替えることができます。 - この機能をオンにすると、**ステージが配置されているマップ画面**で自動戦闘を開始できます。 自動戦闘キューは、理性不足/戦闘失敗した/星3以外で完了の場合に停止します。 - リスト内のステージが同じエリアにあることを確認してください(マップ画面を左右にスワイプすることでのみナビゲートできます)。 - **攻略ファイルの採点を高め、クリエイターを激励するために、必ず良質な攻略ファイルに「いいね!」を押してください。** @@ -153,7 +153,7 @@ icon: ic:baseline-article - マップ座標の取得: - ジョブエディターでステージ名を入力すると、ドラッグ可能な座標マップが左下隅に自動的にロードされ、クリックして現在のオペレーターの位置を設定できます。 - ステージ名を入力して JSON をエクスポートすると、直接行動開始され、座標情報で覆われたマップのスクリーンショットが MAA ディレクトリの `debug\map` ディレクトリに生成されます。 - - [PRTS.map](https://map.ark-nights.com/) の `設定` から座標を `MAA` に変更し使います。 + - [PRTS.map](https://map.ark-nights.com/) の `設定` から座標を `MAA` に変更し使います。 - 演習モードをサポートしている。 - 説明文には、自分の名前(作者名)、参考動画のURL、その他言いたいことなどを記入することをお勧めします - QQディスカッショングループ [1169188429](https://jq.qq.com/?_wv=1027&k=QZcGcJ9G)(中国語のみ) に参加して、攻略ファイルの作成やその他の問題について私たちと議論することを歓迎します。 @@ -163,13 +163,13 @@ icon: ic:baseline-article - 自動ジャンプに失敗した場合は、倉庫の `材料` インターフェースに手動で切り替え、**左端にスワイプ**して機能を開始してください。 - 現在の対応データサイトは、 [Arkplanner](https://penguin-stats.io/planner) 、 [アークナイツ ツールボックス](https://arkntools.app/#/material) 、 [ARK-NIGHTS.com](https://ark-nights.com/settings)。 - もしかしたら、後でもっと便利な機能を実行するために使われるかもしれません、多分。 -- あなたがデータサイトのウェブマスターであるならば、あなたのサイトの材料JSONプロトコルを適応させるために私達に連絡することも大歓迎です。 +- あなたがデータサイトのウェブマスターであるならば、あなたのサイトの材料JSONプロトコルを適応させるために私達に連絡することも大歓迎です。 ## 設定の紹介 Windows MAAには `設定` タブの他に `タスク設定` もあります。 `スタート` のタスクリスト右側の `歯車` をクリックするとスタート内の異なるタスク設定に切り替えることができます〜 - `一般設定` `高度な設定` をクリックすると、 `タスク設定` も切り替わるので注意してください~ +`一般設定` `高度な設定` をクリックすると、 `タスク設定` も切り替わるので注意してください~ ### カスタム接続 @@ -181,7 +181,6 @@ Windows MAAには `設定` タブの他に `タスク設定` もあります。 #### ポート番号の取得 - 方法1:adbコマンドを使用して実行ポートを直接確認する - 1. **一つの**エミュレータを起動し、このコンピューターに他の Android デバイスが接続されていないことを確認します。 2. ADB実行可能ファイルが保存されているフォルダ内のコマンドウィンドウを起動します。 3. 以下のコマンドを実行します: @@ -203,7 +202,6 @@ Windows MAAには `設定` タブの他に `タスク設定` もあります。 接続アドレスとして `127.0.0.1:[ADBPORT]` を使用します(`[ADBPORT]`を実際の数字に置き換えます)。 `emulator-****` を出力する場合は、方法2を参照してください。 - 方法2: 確立されたADB接続を確認する - 1. 方法1 を実行します。 2. `Logo Key + S` を押して検索バーを開き、 `Resource Monitor` と入力すると開きます。 3. `ネットワーク` タブに切り替えて、 `listening port` の `名前` 列でエミュレータ プロセス名 (`HD-Player.exe` など) を探します。 @@ -251,7 +249,7 @@ Windows MAAには `設定` タブの他に `タスク設定` もあります。 ::: details 示例 - ```text +```text マルチインスタンス1: エミュレータのパス:C:\ProgramData\Microsoft\Windows\Start Menu\Programs\BlueStacks\マルチインスタンス1.lnk マルチインスタンス2: diff --git a/docs/ja-jp/manual/introduction/others.md b/docs/ja-jp/manual/introduction/others.md index f3b6bf7baa..a20f499d33 100644 --- a/docs/ja-jp/manual/introduction/others.md +++ b/docs/ja-jp/manual/introduction/others.md @@ -2,6 +2,7 @@ order: 11 icon: icon-park-solid:other --- + # その他 ## GPU 推論加速 @@ -14,7 +15,7 @@ DirectML を使用して GPU による認識推論を加速[PR](https://git メイン画面と設定での設定変更は通常自動保存されますが、以下の項目は MAA 再起動後にリセットされます。 - `*` マークが付いたオプション -- `(一回のみ)` マークが付いたオプション +- `(一回のみ)` マークが付いたオプション - チェックボックスを右クリックして得られる半選択スイッチ - diff --git a/docs/ja-jp/manual/introduction/reclamation-algorithm.md b/docs/ja-jp/manual/introduction/reclamation-algorithm.md index 2c0825edc8..82c837532f 100644 --- a/docs/ja-jp/manual/introduction/reclamation-algorithm.md +++ b/docs/ja-jp/manual/introduction/reclamation-algorithm.md @@ -2,6 +2,7 @@ order: 8 icon: solar:streets-map-point-linear --- + # 生息演算 ::: important Translation Required diff --git a/docs/ja-jp/manual/introduction/rewards.md b/docs/ja-jp/manual/introduction/rewards.md index 7cda0026e0..585aba96c7 100644 --- a/docs/ja-jp/manual/introduction/rewards.md +++ b/docs/ja-jp/manual/introduction/rewards.md @@ -2,6 +2,7 @@ order: 6 icon: lucide:gift --- + # 報酬受取 毎日の報酬と毎週の報酬を自動受取します。 diff --git a/docs/ja-jp/protocol/callback-schema.md b/docs/ja-jp/protocol/callback-schema.md index 764ce13d2e..dbe8831cb7 100644 --- a/docs/ja-jp/protocol/callback-schema.md +++ b/docs/ja-jp/protocol/callback-schema.md @@ -22,41 +22,41 @@ typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom ## 概要 - `int msg` - The message type + The message type - ```cpp - enum class AsstMsg - { - /* Global Info */ - InternalError = 0, // 内部エラー - InitFailed = 1, // 初期化に失敗しました - ConnectionInfo = 2, // 接続情報 - AllTasksCompleted = 3, // すべてのタスクが完了したかどうか - AsyncCallInfo = 4, // 外部非同期呼び出し情報 + ```cpp + enum class AsstMsg + { + /* Global Info */ + InternalError = 0, // 内部エラー + InitFailed = 1, // 初期化に失敗しました + ConnectionInfo = 2, // 接続情報 + AllTasksCompleted = 3, // すべてのタスクが完了したかどうか + AsyncCallInfo = 4, // 外部非同期呼び出し情報 - /* TaskChain Info */ - TaskChainError = 10000, // 一連のタスク 実行/認識のエラー - TaskChainStart = 10001, // 一連のタスク 開始 - TaskChainCompleted = 10002, // 一連のタスク 完了 - TaskChainExtraInfo = 10003, // 一連のタスクの追加情報 - TaskChainStopped = 10004, // 一連のタスク 手動停止 + /* TaskChain Info */ + TaskChainError = 10000, // 一連のタスク 実行/認識のエラー + TaskChainStart = 10001, // 一連のタスク 開始 + TaskChainCompleted = 10002, // 一連のタスク 完了 + TaskChainExtraInfo = 10003, // 一連のタスクの追加情報 + TaskChainStopped = 10004, // 一連のタスク 手動停止 - /* SubTask Info */ - SubTaskError = 20000, // サブタスク 実行/認識におけるエラー - SubTaskStart = 20001, // サブタスク 実行 - SubTaskCompleted = 20002, // サブタスク 完了 - SubTaskExtraInfo = 20003, // サブタスクの追加情報 - SubTaskStopped = 20004, // サブタスク 手動停止 + /* SubTask Info */ + SubTaskError = 20000, // サブタスク 実行/認識におけるエラー + SubTaskStart = 20001, // サブタスク 実行 + SubTaskCompleted = 20002, // サブタスク 完了 + SubTaskExtraInfo = 20003, // サブタスクの追加情報 + SubTaskStopped = 20004, // サブタスク 手動停止 - /* Web Request */ - ReportRequest = 30000, // レポートリクエスト - }; - ``` + /* Web Request */ + ReportRequest = 30000, // レポートリクエスト + }; + ``` - `const char* details` - メッセージの詳細, JSON. 詳細: [Field Description](#field-description) + メッセージの詳細, JSON. 詳細: [Field Description](#field-description) - `void* custom_arg` - 呼び出し元のカスタム引数には、 `AsstCreateEx` インターフェースの `custom_arg` 引数が渡される。C ライクな言語では、`this` ポインタを一緒に渡すことができる。 + 呼び出し元のカスタム引数には、 `AsstCreateEx` インターフェースの `custom_arg` 引数が渡される。C ライクな言語では、`this` ポインタを一緒に渡すことができる。 ## Field Description @@ -92,25 +92,25 @@ Todo ### 多用される `What` フィルドの値 - `ConnectFailed` - 接続失敗 + 接続失敗 - `Connected` - 接続成功。現段階では `uuid` フィールドが空であることに注意してください (次のステップで取得されます) + 接続成功。現段階では `uuid` フィールドが空であることに注意してください (次のステップで取得されます) - `UuidGot` - UUID の取得 + UUID の取得 - `UnsupportedResolution` - この解像度はサポートされていません + この解像度はサポートされていません - `ResolutionError` - 解像度を取得できない + 解像度を取得できない - `Reconnecting` - 接続切断 (adb/emulator クラッシュ), 再接続開始 + 接続切断 (adb/emulator クラッシュ), 再接続開始 - `Reconnected` - 接続切断 (adb/emulator クラッシュ), 再接続成功 + 接続切断 (adb/emulator クラッシュ), 再接続成功 - `Disconnect` - 接続切断 (adb/emulator クラッシュ), 再接続失敗 + 接続切断 (adb/emulator クラッシュ), 再接続失敗 - `ScreencapFailed` - 画面取得失敗 (adb/emulator クラッシュ), 再接続失敗 + 画面取得失敗 (adb/emulator クラッシュ), 再接続失敗 - `TouchModeNotAvailable` - サポートされていないタッチモード + サポートされていないタッチモード ### AsyncCallInfo @@ -142,39 +142,39 @@ Todo #### 多用される `taskchain` フィールドの値 - `StartUp` - ゲーム開始 + ゲーム開始 - `CloseDown` - ゲームを閉じる + ゲームを閉じる - `Fight` - 作戦 + 作戦 - `Mall` - FPとFP交換所に買い物 + FPとFP交換所に買い物 - `Recruit` - 自動公開求人 + 自動公開求人 - `Infrast` - 基地施設 + 基地施設 - `Award` - デイリー報酬を受け取る + デイリー報酬を受け取る - `Roguelike` - 統合戦略 + 統合戦略 - `Copilot` - 自動作戦 + 自動作戦 - `SSSCopilot` - 自動保全駐在作戦 + 自動保全駐在作戦 - `Depot` - 倉庫の識別 + 倉庫の識別 - `OperBox` - オペレーターボックス識別 + オペレーターボックス識別 - `Reclamation` - 生息演算 + 生息演算 - `Custom` - カストム タスク + カストム タスク - `SingleStep` - サブタスク + サブタスク - `VideoRecognition` - ビデオ認識タスク + ビデオ認識タスク - `Debug` - デバッグ + デバッグ ### TaskChain 関連情報 @@ -205,69 +205,69 @@ Todo #### 多用される `subtask` フィールドの値 -- `ProcessTask` +- `ProcessTask` - ```json - // 対応する詳細フィールドの例 - { - "task": "StartButton2", // タスク名 - "action": 512, - "exec_times": 1, // 実行回数 - "max_times": 999, // 最大実行回数 - "algorithm": 0 - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "task": "StartButton2", // タスク名 + "action": 512, + "exec_times": 1, // 実行回数 + "max_times": 999, // 最大実行回数 + "algorithm": 0 + } + ``` - Todo Other ##### 多用される `task` フィールドの値 - `StartButton2` - 開始 + 開始 - `MedicineConfirm` - 理性回復剤使用確認 + 理性回復剤使用確認 - `ExpiringMedicineConfirm` - 48時間以内に期限が切れる理性回復剤使用確認 + 48時間以内に期限が切れる理性回復剤使用確認 - `StoneConfirm` - 純正源石使用確認 + 純正源石使用確認 - `RecruitRefreshConfirm` - 公開求人リストの更新確認 + 公開求人リストの更新確認 - `RecruitConfirm` - 公開求人の確認 + 公開求人の確認 - `RecruitNowConfirm` - 緊急招集票の使用確認 + 緊急招集票の使用確認 - `ReportToPenguinStats` - ペンギン急便への報告 + ペンギン急便への報告 - `ReportToYituliu` - Yituliu へビッグデータの報告 + Yituliu へビッグデータの報告 - `InfrastDormDoubleConfirmButton` - 基地施設での二重確認は、他のオペレーターとの競合がある場合のみ発生します + 基地施設での二重確認は、他のオペレーターとの競合がある場合のみ発生します - `StartExplore` - 統合戦略: 開始 + 統合戦略: 開始 - `StageTraderInvestConfirm` - 統合戦略: 源石錐とアイテム交換 + 統合戦略: 源石錐とアイテム交換 - `StageTraderInvestSystemFull` - 統合戦略: 投資満額 + 統合戦略: 投資満額 - `ExitThenAbandon` - 統合戦略: 終了確認 + 統合戦略: 終了確認 - `MissionCompletedFlag` - 統合戦略: ミッション完了 + 統合戦略: ミッション完了 - `MissionFailedFlag` - 統合戦略: ミッション失敗 + 統合戦略: ミッション失敗 - `StageTraderEnter` - 統合戦略: 怪しい旅商人 + 統合戦略: 怪しい旅商人 - `StageSafeHouseEnter` - 統合戦略: 安全な片隅 + 統合戦略: 安全な片隅 - `StageEncounterEnter` - 統合戦略: 思わぬ遭遇 + 統合戦略: 思わぬ遭遇 - `StageCombatDpsEnter` - 統合戦略: 作戦 + 統合戦略: 作戦 - `StageEmergencyDps` - 統合戦略: 緊急作戦 + 統合戦略: 緊急作戦 - `StageDreadfulFoe` - 統合戦略: 悪路凶敵 + 統合戦略: 悪路凶敵 - `StartGameTask` - クライアントの起動に失敗 (client_type と設定ファイルの互換性なし) + クライアントの起動に失敗 (client_type と設定ファイルの互換性なし) - Todo Other ### SubTaskExtraInfo @@ -285,343 +285,343 @@ Todo #### 多用される `what` と `details` フィールドの値 - `StageDrops` - ステージドロップインフォメーション + ステージドロップインフォメーション - ```json - // 対応する詳細フィールドの例 - { - "drops": [ // 今回のドロップされた素材 - { - "itemId": "3301", - "quantity": 2, - "itemName": "アーツ学1" - }, - { - "itemId": "3302", - "quantity": 1, - "itemName": "アーツ学2" - }, - { - "itemId": "3303", - "quantity": 2, - "itemName": "アーツ学3" - } - ], - "stage": { // レベル情報 - "stageCode": "CA-5", - "stageId": "wk_fly_5" - }, - "stars": 3, // ステージクリア評価 - "stats": [ // この実行中にドロップされた素材の総量 - { - "itemId": "3301", - "itemName": "アーツ学1", - "quantity": 4, - "addQuantity": 2 // 今回の新規ドロップ数 - }, - { - "itemId": "3302", - "itemName": "アーツ学2", - "quantity": 3, - "addQuantity": 1 - }, - { - "itemId": "3303", - "itemName": "アーツ学3", - "quantity": 4, - "addQuantity": 2 - } - ] - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "drops": [ // 今回のドロップされた素材 + { + "itemId": "3301", + "quantity": 2, + "itemName": "アーツ学1" + }, + { + "itemId": "3302", + "quantity": 1, + "itemName": "アーツ学2" + }, + { + "itemId": "3303", + "quantity": 2, + "itemName": "アーツ学3" + } + ], + "stage": { // レベル情報 + "stageCode": "CA-5", + "stageId": "wk_fly_5" + }, + "stars": 3, // ステージクリア評価 + "stats": [ // この実行中にドロップされた素材の総量 + { + "itemId": "3301", + "itemName": "アーツ学1", + "quantity": 4, + "addQuantity": 2 // 今回の新規ドロップ数 + }, + { + "itemId": "3302", + "itemName": "アーツ学2", + "quantity": 3, + "addQuantity": 1 + }, + { + "itemId": "3303", + "itemName": "アーツ学3", + "quantity": 4, + "addQuantity": 2 + } + ] + } + ``` - `RecruitTagsDetected` - 採用タグの検出 + 採用タグの検出 - ```json - // 対応するフィールドの詳細 - { - "tags": [ - "COST回復", - "防御", - "先鋒タイプ", - "補助タイプ", - "近距離" - ] - } - ``` + ```json + // 対応するフィールドの詳細 + { + "tags": [ + "COST回復", + "防御", + "先鋒タイプ", + "補助タイプ", + "近距離" + ] + } + ``` - `RecruitSpecialTag` - 特別な採用タグの検出 + 特別な採用タグの検出 - ```json - // 対応する詳細フィールドの例 - { - "tag": "上級エリート" - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "tag": "上級エリート" + } + ``` - `RecruitResult` - 公開求人結果 + 公開求人結果 - ```json - // 対応する詳細フィールドの例 - { - "tags": [ // 全てのタグ、今のところは5つに違いない - "弱化", - "減速", - "術師タイプ", - "補助タイプ", - "近距離" - ], - "level": 4, // 総合的なレアリティ - "result": [ - { - "tags": [ - "弱化" - ], - "level": 4, // レアリティに対応するタグ - "opers": [ - { - "name": "プラマニクス", - "level": 5 // レアリティに対応するオペレーター - }, - { - "name": "メテオリーテ", - "level": 5 - }, - { - "name": "ワイフー", - "level": 5 - }, - { - "name": "ヘイズ", - "level": 4 - }, - { - "name": "メテオ", - "level": 4 - } - ] - }, - { - "tags": [ - "減速", - "術師タイプ" - ], - "level": 4, - "opers": [ - { - "name": "ナイトメア", - "level": 5 - }, - { - "name": "グレイ", - "level": 4 - } - ] - }, - { - "tags": [ - "弱化", - "術師タイプ" - ], - "level": 4, - "opers": [ - { - "name": "ヘイズ", - "level": 4 - } - ] - } - ] - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "tags": [ // 全てのタグ、今のところは5つに違いない + "弱化", + "減速", + "術師タイプ", + "補助タイプ", + "近距離" + ], + "level": 4, // 総合的なレアリティ + "result": [ + { + "tags": [ + "弱化" + ], + "level": 4, // レアリティに対応するタグ + "opers": [ + { + "name": "プラマニクス", + "level": 5 // レアリティに対応するオペレーター + }, + { + "name": "メテオリーテ", + "level": 5 + }, + { + "name": "ワイフー", + "level": 5 + }, + { + "name": "ヘイズ", + "level": 4 + }, + { + "name": "メテオ", + "level": 4 + } + ] + }, + { + "tags": [ + "減速", + "術師タイプ" + ], + "level": 4, + "opers": [ + { + "name": "ナイトメア", + "level": 5 + }, + { + "name": "グレイ", + "level": 4 + } + ] + }, + { + "tags": [ + "弱化", + "術師タイプ" + ], + "level": 4, + "opers": [ + { + "name": "ヘイズ", + "level": 4 + } + ] + } + ] + } + ``` - `RecruitTagsRefreshed` - 公開求人タグの更新 + 公開求人タグの更新 - ```json - // 対応する詳細フィールドの例 - { - "count": 1, // スロットが更新された回数 - "refresh_limit": 3 // 更新最大回数 - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "count": 1, // スロットが更新された回数 + "refresh_limit": 3 // 更新最大回数 + } + ``` - `RecruitNoPermit` - 求人票が切れた + 求人票が切れた - ```json - // 対応する詳細フィールドの例 - { - "continue": true, // 更新を続けるかどうか - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "continue": true, // 更新を続けるかどうか + } + ``` - `RecruitTagsSelected` - 公開求人タグの選択 + 公開求人タグの選択 - ```json - // 対応する詳細フィールドの例 - { - "tags": [ - "減速", - "術師タイプ" - ] - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "tags": [ + "減速", + "術師タイプ" + ] + } + ``` - `RecruitSlotCompleted` - 公開求人スロットの完了 + 公開求人スロットの完了 - `RecruitError` - 公開求人認識時のエラー + 公開求人認識時のエラー - `EnterFacility` - 施設へ入る + 施設へ入る - ```json - // 対応する詳細フィールドの例 - { - "facility": "Mfg", // 施設名 - "index": 0 // 施設 ID - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "facility": "Mfg", // 施設名 + "index": 0 // 施設 ID + } + ``` - `NotEnoughStaff` - オペレーター不足 + オペレーター不足 - ```json - // 対応する詳細フィールドの例 - { - "facility": "Mfg", // 施設名 - "index": 0 // 施設 ID - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "facility": "Mfg", // 施設名 + "index": 0 // 施設 ID + } + ``` - `ProductOfFacility` - 施設の生産 + 施設の生産 - ```json - // 対応する詳細フィールドの例 - { - "product": "Money", // 生産物 - "facility": "Mfg", // 施設名 - "index": 0 // 施設 ID - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "product": "Money", // 生産物 + "facility": "Mfg", // 施設名 + "index": 0 // 施設 ID + } + ``` - `StageInfo` - 自動戦闘ステージの情報 + 自動戦闘ステージの情報 - ```json - // 対応する詳細フィールドの例 - { - "name": string // ステージ名 - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "name": string // ステージ名 + } + ``` - `StageInfoError` - 自動戦闘ステージの情報エラー + 自動戦闘ステージの情報エラー - `PenguinId` - PenguinStats ID + PenguinStats ID - ```json - // 対応する詳細フィールドの例 - { - "id": string - } - ``` + ```json + // 対応する詳細フィールドの例 + { + "id": string + } + ``` - `DepotInfo` - 倉庫のアイテムの認識結果 + 倉庫のアイテムの認識結果 - ```json - // 対応する詳細フィールドの例 - "done": bool, // 認識が完了したかどうか,false はまだ進行中かどうか(処理中のデータ) - "arkplanner": { // https://penguin-stats.cn/planner - "object": { - "items": [ - { - "id": "2004", - "have": 4, - "name": "上級作戦記録" - }, - { - "id": "mod_unlock_token", - "have": 25, - "name": "モジュールデータ" - }, - { - "id": "2003", - "have": 20, - "name": "中級作戦記録" - } - ], - "@type": "@penguin-statistics/depot" - }, - "data": "{\"@type\":\"@penguin-statistics/depot\",\"items\":[{\"id\":\"2004\",\"have\":4,\"name\":\"上級作戦記録\"},{\"id\":\"mod_unlock_token\",\"have\":25,\"name\":\"モジュールデータ\"},{\"id\":\"2003\",\"have\":20,\"name\":\"中級作戦記録\"}]}" - }, - "lolicon": { // https://arkntools.app/#/material - "object": { - "2004" : 4, - "mod_unlock_token": 25, - "2003": 20 - }, - "data": "{\"2003\":20,\"2004\": 4,\"mod_unlock_token\": 25}" - } - // 現在は ArkPlanner と Lolicon (Arkntools) 形式のみ対応、今後対応するサイトが増える可能性あり - ``` + ```json + // 対応する詳細フィールドの例 + "done": bool, // 認識が完了したかどうか,false はまだ進行中かどうか(処理中のデータ) + "arkplanner": { // https://penguin-stats.cn/planner + "object": { + "items": [ + { + "id": "2004", + "have": 4, + "name": "上級作戦記録" + }, + { + "id": "mod_unlock_token", + "have": 25, + "name": "モジュールデータ" + }, + { + "id": "2003", + "have": 20, + "name": "中級作戦記録" + } + ], + "@type": "@penguin-statistics/depot" + }, + "data": "{\"@type\":\"@penguin-statistics/depot\",\"items\":[{\"id\":\"2004\",\"have\":4,\"name\":\"上級作戦記録\"},{\"id\":\"mod_unlock_token\",\"have\":25,\"name\":\"モジュールデータ\"},{\"id\":\"2003\",\"have\":20,\"name\":\"中級作戦記録\"}]}" + }, + "lolicon": { // https://arkntools.app/#/material + "object": { + "2004" : 4, + "mod_unlock_token": 25, + "2003": 20 + }, + "data": "{\"2003\":20,\"2004\": 4,\"mod_unlock_token\": 25}" + } + // 現在は ArkPlanner と Lolicon (Arkntools) 形式のみ対応、今後対応するサイトが増える可能性あり + ``` - `OperBoxInfo` - オペレーターボックス識別結果 + オペレーターボックス識別結果 - ```json - // 対応する詳細フィールドの例 - "done": bool, // 認識が完了したかどうか,false はまだ進行中かどうか(処理中のデータ) - "all_oper": [ - { - "id": "char_002_amiya", - "name": "阿米娅", - "own": true - }, - { - "id": "char_003_kalts", - "name": "凯尔希", - "own": true - }, - { - "id": "char_1020_reed2", - "name": "焰影苇草", - "own": false - }, - ] - "own_opers": [ - { - "id": "char_002_amiya", // オペレーターID - "name": "阿米娅", // 氏名、中国語で出力 - "own": true, // 持っているかどうか - "elite": 2, // 昇進段階 0, 1, 2 - "level": 50, // レベル - "potential": 6, // 潜在 [1, 6] - "rarity": 5 // レア度 [1, 6] - }, - { - "id": "char_003_kalts", - "name": "凯尔希", - "own": true, - "elite": 2, - "level": 50, - "potential": 1, - "rarity": 6 - } - ] - ``` + ```json + // 対応する詳細フィールドの例 + "done": bool, // 認識が完了したかどうか,false はまだ進行中かどうか(処理中のデータ) + "all_oper": [ + { + "id": "char_002_amiya", + "name": "阿米娅", + "own": true + }, + { + "id": "char_003_kalts", + "name": "凯尔希", + "own": true + }, + { + "id": "char_1020_reed2", + "name": "焰影苇草", + "own": false + }, + ] + "own_opers": [ + { + "id": "char_002_amiya", // オペレーターID + "name": "阿米娅", // 氏名、中国語で出力 + "own": true, // 持っているかどうか + "elite": 2, // 昇進段階 0, 1, 2 + "level": 50, // レベル + "potential": 6, // 潜在 [1, 6] + "rarity": 5 // レア度 [1, 6] + }, + { + "id": "char_003_kalts", + "name": "凯尔希", + "own": true, + "elite": 2, + "level": 50, + "potential": 1, + "rarity": 6 + } + ] + ``` - `UnsupportedLevel` - 自動作戦で、サポートされていないレベル名 + 自動作戦で、サポートされていないレベル名 ### ReportRequest diff --git a/docs/ja-jp/protocol/copilot-schema.md b/docs/ja-jp/protocol/copilot-schema.md index cb1dc73eb1..362f825a72 100644 --- a/docs/ja-jp/protocol/copilot-schema.md +++ b/docs/ja-jp/protocol/copilot-schema.md @@ -28,7 +28,7 @@ JSONファイルはコメントをサポートしておらず、テキスト内 // 2 - X回使用(例えば、マウンテン スキル2は1回、チョンユエ スキル3は5回、"skill_times" フィールドで設定) // 3 - 自動判定 (未実装) // 自動発動のスキルであれば0を記入 - + "skill_times": 5, // スキル使用回数。オプション、デフォルトは1 "requirements": { // 要件、予約フィールド、未実装、オプション、デフォルトは空白 @@ -110,7 +110,7 @@ JSONファイルはコメントをサポートしておらず、テキスト内 // 上記例の場合 1 に設定してください "skill_times": 5, // スキル使用回数。オプション、デフォルトは1 - + "pre_delay": 0, // 事前遅延 ms(ミリ秒), オプション, デフォルトは 0 "post_delay": 0, // 事後遅延 ms(ミリ秒), オプション, デフォルトは 0 diff --git a/docs/ja-jp/protocol/integrated-strategy-schema.md b/docs/ja-jp/protocol/integrated-strategy-schema.md index 8cb7d8a969..b67a077cd3 100644 --- a/docs/ja-jp/protocol/integrated-strategy-schema.md +++ b/docs/ja-jp/protocol/integrated-strategy-schema.md @@ -52,6 +52,7 @@ JSONファイルはコメントをサポートしていません。テキスト 3. 既存のグループ名を変更しないでください。 MAA の更新時に以前のバージョンの作業が使用できなくなる可能性があります 4. 新しいグループを追加しないようにし、新しく追加されたユニットを使用法に基づいて既存のグループに組み込むようにしてください + ::: ::: tip @@ -87,31 +88,31 @@ JSONファイルはコメントをサポートしていません。テキスト ファントムテーマを例に取ると:主にオペレーターを以下のように分類しています - | グループ | 主な考慮事項 | 主に職種を含む | オペレーターの例 | - | :--- | :--- | :--- | :--- | - | **_地面阻挡_** | 場に立つことと雑魚を清掃 | 重装、前衛 | 庇護衛士、基石、ラ・プルマ、マウンテン、M3、リィンとシーンの召喚ユニット、スポット、重装予備隊員 | - | **_地面单切_** | 一人でエリートモンスターと戦う | 執行者-特殊 | スルト、血掟テキサス、キリンRヤトウ、M3、レッド | - | **_高台 C_** | 常態と決戦DPS | 狙撃、術師 | 遊龍チェン、ゴールデングロー、エイヤフィヤトラ、フィアメッタ | - | **_高台输出_** | 対空および通常DPS | 狙撃、術師 | アルケット、エクシア、クルース、スチュワード | - | **_奶_** | 治療能力 | 医療、補助 | ケルシ、濁心スカジ、ハイビスカス、アンセル | - | **_回费_** | cost 回復 | 先鋒 | テンニンカ、イネス、フェン、バニラ | - | **_炮灰_** | 砲弾吸収、再配置 | 特殊、召喚ユニット | M3、レッド、テンニンカ、予備隊員 | - | **_高台预备_** | DPS能力を持っています | | オーキッド、予備隊員 | + | グループ | 主な考慮事項 | 主に職種を含む | オペレーターの例 | + | :------------- | :----------------------------- | :----------------- | :----------------------------------------------------------------------------------------------- | + | **_地面阻挡_** | 場に立つことと雑魚を清掃 | 重装、前衛 | 庇護衛士、基石、ラ・プルマ、マウンテン、M3、リィンとシーンの召喚ユニット、スポット、重装予備隊員 | + | **_地面单切_** | 一人でエリートモンスターと戦う | 執行者-特殊 | スルト、血掟テキサス、キリンRヤトウ、M3、レッド | + | **_高台 C_** | 常態と決戦DPS | 狙撃、術師 | 遊龍チェン、ゴールデングロー、エイヤフィヤトラ、フィアメッタ | + | **_高台输出_** | 対空および通常DPS | 狙撃、術師 | アルケット、エクシア、クルース、スチュワード | + | **_奶_** | 治療能力 | 医療、補助 | ケルシ、濁心スカジ、ハイビスカス、アンセル | + | **_回费_** | cost 回復 | 先鋒 | テンニンカ、イネス、フェン、バニラ | + | **_炮灰_** | 砲弾吸収、再配置 | 特殊、召喚ユニット | M3、レッド、テンニンカ、予備隊員 | + | **_高台预备_** | DPS能力を持っています | | オーキッド、予備隊員 | 2. 特別な操作が必要なグループ 上記のような一般的なグループ以外に、時折、特定のオペレーターやオペレーターの種類に対して細かいカスタマイズが必要な場合があります。例えば - | グループ | 含まれるオペレーター | 主な特徴 | - | :--- | :--- | :--- | - | 棘刺 | ソーンズ、ホルン | 地上遠隔攻撃、特定の位置に非常に適したマップがあります | - | 召唤类 | ケルシ、リィン、シーン | 地上ブロックを持ち、一部のマップでは優先的に配置する必要があり、召喚物はブロックまたは死体として使用できます | - | 情报官 | カンタービレ、イネス | コスト回収やサイドアウトプット、シングルカットが可能 | - | 浊心斯卡蒂 | 濁心スカジ | 低圧時の回復量はまあまあですが、範囲が特殊で、一部のマップには特に適しています | - | 焰苇 | 焔影リード | サーミローグはよく開局オペレーターを使い、治療と輸出を兼ねており、いくつかの図には比較的適切な位置がある | - | 银灰 | シルバーアッシュ、ムリナール | 地上の大規模な戦闘出力、ボスに対して配置できます | - | 史尔特尔 | スルト | 精二後、3スキルを固定搭載するため、この時点でのスタンバイ能力はほぼゼロで、ブロック位置の配置優先度は非常に低いです | - | 骰子 | ダイス | ミヅキテーマの中のダイスは個別に操作する必要があります | + | グループ | 含まれるオペレーター | 主な特徴 | + | :--------- | :--------------------------- | :------------------------------------------------------------------------------------------------------------------ | + | 棘刺 | ソーンズ、ホルン | 地上遠隔攻撃、特定の位置に非常に適したマップがあります | + | 召唤类 | ケルシ、リィン、シーン | 地上ブロックを持ち、一部のマップでは優先的に配置する必要があり、召喚物はブロックまたは死体として使用できます | + | 情报官 | カンタービレ、イネス | コスト回収やサイドアウトプット、シングルカットが可能 | + | 浊心斯卡蒂 | 濁心スカジ | 低圧時の回復量はまあまあですが、範囲が特殊で、一部のマップには特に適しています | + | 焰苇 | 焔影リード | サーミローグはよく開局オペレーターを使い、治療と輸出を兼ねており、いくつかの図には比較的適切な位置がある | + | 银灰 | シルバーアッシュ、ムリナール | 地上の大規模な戦闘出力、ボスに対して配置できます | + | 史尔特尔 | スルト | 精二後、3スキルを固定搭載するため、この時点でのスタンバイ能力はほぼゼロで、ブロック位置の配置優先度は非常に低いです | + | 骰子 | ダイス | ミヅキテーマの中のダイスは個別に操作する必要があります | ::: info 注意 現在、識別されていない近距離オペレーターは最後から2番目のグループ(其他地面)に分類され、識別されていない遠距離オペレーターは最後から1番目のグループ(其他高台)に分類されます @@ -217,7 +218,6 @@ JSONファイルはコメントをサポートしていません。テキスト ### MAA ローグの基本戦闘ロジック--パラスちゃんの高血圧の源 1. マップ上のタイルの種類に基づいた基本的な戦闘操作 - - MAA はマップ上のタイルが青い扉か赤い扉か、高台か地面か、配置可能かどうかに基づいて基本的な戦闘操作を行います。 - MAA はマップの名前や番号に基づいてどの作業を使用するかを決定し、マップの**一般**、**緊急**、**ルートネット**、**暗号板使用**などの状況を判断しません。 @@ -226,7 +226,6 @@ JSONファイルはコメントをサポートしていません。テキスト したがって、後で、**すべての異なる状況**(上記で言及した状況)に対処できる戦闘ロジックを設計する必要があります。皆に「このマップの操作は高血圧だ!」とissueで言われないように気をつけてください(笑) 2. MAA の基本的な作戦戦略--青い扉を封鎖 - 1. 地面オペレーターは青い扉のタイルに優先して配置されます(なぜタイル上なのかは後で説明)、またはその周囲に配置され、方向は赤い扉に向けられます(自動計算)。 2. 地面を優先して配置し、その後治療オペレーターや高台オペレーターを配置し、青い扉から周囲に向かって一周ずつ配置します。 diff --git a/docs/ja-jp/protocol/integration.md b/docs/ja-jp/protocol/integration.md index a868707a8a..70ee68245a 100644 --- a/docs/ja-jp/protocol/integration.md +++ b/docs/ja-jp/protocol/integration.md @@ -26,22 +26,22 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p #### Return Value - `TaskId` - 以下の構成で、タスクの追加に成功した場合のタスクID; - タスクの追加に失敗した場合は0。 + 以下の構成で、タスクの追加に成功した場合のタスクID; + タスクの追加に失敗した場合は0。 #### Parameter Description - `AsstHandle handle` - Instance handle + Instance handle - `const char* type` - Task type + Task type - `const char* params` - Task parameters in JSON + Task parameters in JSON ##### List of Task Types - `StartUp` - Start-up + Start-up ```json5 // 対応するタスクのパラメータ @@ -58,7 +58,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `CloseDown` - ゲームを閉じる + ゲームを閉じる ```json5 // 対応するタスクのパラメータ @@ -70,7 +70,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Fight` - Operation + Operation ```json5 // 対応するタスクのパラメータ @@ -109,7 +109,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p いくつかの特別ステージ名もサポートしています、[組み込み例](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/tools/AutoLocalization/example/ja-jp.xaml#L230)をご参照ください - `Recruit` - 公開求人 + 公開求人 ```json5 // 対応するタスクのパラメータ @@ -151,7 +151,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Infrast` - 基地シフト + 基地シフト ```json5 { @@ -179,8 +179,8 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Mall` - FPの回収と自動購入 - 最初に `buy_first` にあるものを左から右に押して順番に一度購入し、次に左から右に2回購入して`blacklist` を回避し、FPオーバーフローの場合はブラックリストを無視して、オーバーフローしなくなるまで左から右に3回目に購入します。 + FPの回収と自動購入 + 最初に `buy_first` にあるものを左から右に押して順番に一度購入し、次に左から右に2回購入して`blacklist` を回避し、FPオーバーフローの場合はブラックリストを無視して、オーバーフローしなくなるまで左から右に3回目に購入します。 ```json5 // 対応するタスクのパラメータ @@ -206,7 +206,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Award` - 報酬の受け取り + 報酬の受け取り ```json5 // 対応するタスクのパラメータ @@ -216,7 +216,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Roguelike` - 統合戦略 + 統合戦略 ```json5 // 対応するタスクパラメータ @@ -282,7 +282,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Copilot` - 自動戦闘 + 自動戦闘 ```json5 { @@ -295,7 +295,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p 自動操縦JSONの詳細については、[自動戦闘API](./copilot-schema.md)を参照してください - `SSSCopilot` - 保全駐在の自動戦闘 + 保全駐在の自動戦闘 ```json5 { @@ -308,7 +308,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p 保全駐在の自動操縦JSONの詳細については、[保全駐在API](./sss-schema.md) - `Depot` - 倉庫アイテム認識 + 倉庫アイテム認識 ```json5 // 対応するタスクのパラメータ @@ -318,7 +318,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `OperBox` - カドレー識別 + カドレー識別 ```json5 // 対応するタスクのパラメータ @@ -328,7 +328,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Reclamation` - 生息演算 + 生息演算 ```json5 { @@ -343,7 +343,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p "tools_to_craft": [ string, // 自動的に製造されるアイテム、オプション、デフォルトは螢光棒 ... - ] + ] // サブストリングを入力することをお勧めします "increment_mode": int, // クリックタイプ、オプション、デフォルトは0 // 0 - 連続クリック @@ -353,7 +353,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `Custom` - カスタム タスク + カスタム タスク ```json5 { @@ -367,7 +367,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `SingleStep` - シングル ステップ タスク(現在は戦闘でのみ利用可能) + シングル ステップ タスク(現在は戦闘でのみ利用可能) ```json5 { @@ -385,7 +385,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ``` - `VideoRecognition` - ビデオ認識、現在は作戦ビデオのみ対応 + ビデオ認識、現在は作戦ビデオのみ対応 ```json5 { @@ -409,17 +409,17 @@ bool ASSTAPI AsstSetTaskParams(AsstHandle handle, TaskId id, const char* params) #### Return Value - `bool` - パラメータが正常に設定されたかどうか。 + パラメータが正常に設定されたかどうか。 #### Parameter Description - `AsstHandle handle` - Instance handle + Instance handle - `TaskId task` - Task ID, `AsstAppendTask` の値を返します + Task ID, `AsstAppendTask` の値を返します - `const char* params` - JSONのタスクパラメーター, `AsstAppendTask` と同じ - "動作中に変更はできません" と記載されていないフィールドはランタイム中に変更することができます. そうでなければ、タスクの実行中にこれらの変更は無視される. + JSONのタスクパラメーター, `AsstAppendTask` と同じ + "動作中に変更はできません" と記載されていないフィールドはランタイム中に変更することができます. そうでなければ、タスクの実行中にこれらの変更は無視される. ### `AsstSetStaticOption` @@ -436,14 +436,14 @@ bool ASSTAPI AsstSetStaticOption(AsstStaticOptionKey key, const char* value); #### Return Value - `bool` - 設定が成功したかどうか + 設定が成功したかどうか #### Parameter Description - `AsstStaticOptionKey key` - key + key - `const char* value` - value + value ##### List of Key and value @@ -464,16 +464,16 @@ bool ASSTAPI AsstSetInstanceOption(AsstHandle handle, AsstInstanceOptionKey key, #### Return Value - `bool` - 設定が成功したかどうか + 設定が成功したかどうか #### Parameter Description - `AsstHandle handle` - handle + handle - `AsstInstanceOptionKey key` - key + key - `const char* value` - value + value ##### List of Key and value diff --git a/docs/ja-jp/protocol/remote-control-schema.md b/docs/ja-jp/protocol/remote-control-schema.md index 8e8bedc141..2bfd9a270d 100644 --- a/docs/ja-jp/protocol/remote-control-schema.md +++ b/docs/ja-jp/protocol/remote-control-schema.md @@ -88,7 +88,8 @@ MAA は、エンドポイントを 1 秒間隔で継続的にポーリングし - Settings-[SettingsName] タイプのタスクtypeのオプション値は Settings-ConnectionAddress, Settings-Stage1 - Settings シリーズのタスクは、タスクを受け取ったときにすぐに実行するのではなく、前のタスクの後ろに配置されています。 - すぐに実行される複数のタスクも送信順序で実行されますが、これらのタスクの実行速度は速いため、通常、彼らの順序に注目する必要はありません。 - ::: + +::: ## タスクデータの報告エンドポイント diff --git a/docs/ja-jp/protocol/task-schema.md b/docs/ja-jp/protocol/task-schema.md index 42f4fde87c..61cf003c1d 100644 --- a/docs/ja-jp/protocol/task-schema.md +++ b/docs/ja-jp/protocol/task-schema.md @@ -193,28 +193,28 @@ Template task と base task は、**テンプレートタスク**と総称され - もしタスク "B@A" が `tasks.json` で明示的に定義されていない場合、 `sub` 、 `next` 、 `onErrorNext` 、 `exceededNext` 、 `reduceOtherTimes` のフィールド(もしくはタスク名が `#` で始まる場合は `B`)に `B@` の接頭辞を追加し、残りのパラメータはタスク "A" のものと同じになります。つまり、タスク "A" が以下のパラメータを持つ場合、 - ```json - "A": { - "template": "A.png", - ..., - "next": [ "N1", "N2" ] - } - ``` + ```json + "A": { + "template": "A.png", + ..., + "next": [ "N1", "N2" ] + } + ``` - 以下の両方を定義することと同じです。 + 以下の両方を定義することと同じです。 - ```json - "B@A": { - "template": "A.png", - ..., - "next": [ "B@N1", "B@N2" ] - } - ``` + ```json + "B@A": { + "template": "A.png", + ..., + "next": [ "B@N1", "B@N2" ] + } + ``` - もしタスク "B@A" が `tasks.json` で定義されている場合、以下のルールに従います。 - 1. もし "B@A" の `algorithm` フィールドが "A" のものと異なる場合、派生クラスのパラメータは継承されません(`TaskInfo` によって定義されたパラメータのみが継承されます)。 - 2. 画像マッチングタスクの場合、明示的に定義されていない場合は `template` は `B@A.png` となります("A" の `template` 名を継承するのではなく、派生クラスのパラメータは直接 "A" タスクから継承されます)。 - 3. `TaskInfo` 基底クラスで定義されたパラメータ(`algorithm`、`roi`、`next` などの任意のタスクパラメータの種類)について、"B@A" で明示的に定義されていない場合、これらのパラメータは "A" タスクパラメータから直接継承されます。ただし、前述の5つのフィールド(`sub` など)は、継承時に "B@" が接頭辞として付加されます。 + 1. もし "B@A" の `algorithm` フィールドが "A" のものと異なる場合、派生クラスのパラメータは継承されません(`TaskInfo` によって定義されたパラメータのみが継承されます)。 + 2. 画像マッチングタスクの場合、明示的に定義されていない場合は `template` は `B@A.png` となります("A" の `template` 名を継承するのではなく、派生クラスのパラメータは直接 "A" タスクから継承されます)。 + 3. `TaskInfo` 基底クラスで定義されたパラメータ(`algorithm`、`roi`、`next` などの任意のタスクパラメータの種類)について、"B@A" で明示的に定義されていない場合、これらのパラメータは "A" タスクパラメータから直接継承されます。ただし、前述の5つのフィールド(`sub` など)は、継承時に "B@" が接頭辞として付加されます。 ### Base Task @@ -239,11 +239,11 @@ Virtual task は sharp task (`#` タイプのタスク)とも呼ばれます 名前に `#` を含むタスクは virtual task です。`#` の後には `next`、`back`、`self`、`sub`、`on_error_next`、`exceeded_next`、`reduce_other_times` が続くことがあります。 -| 仮想タスクタイプ | 意味 | 簡単な例 | -|:---------:|:---:|:--------:| -| self | 親タスク名 | `"A": {"next": "#self"}` の `"#self"` は `"A"` と解釈されます。
`"B": {"next": "A@B@C#self"}` の `"A@B@C#self"` は `"B"` と解釈されます。1 | -| back | # の前のタスク名 | `"A@B#back"` は `"A@B"` と解釈されます。
もし直接現れた場合は `"#back"` はスキップされます。 | -| next、sub など | 前のタスク名に対応するフィールド | `next` を例に取ります。
`"A#next"` は `Task.get("A")->next` と解釈されます。
もし直接現れた場合は `"#next"` はスキップされます。 | +| 仮想タスクタイプ | 意味 | 簡単な例 | +| :--------------: | :------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------: | +| self | 親タスク名 | `"A": {"next": "#self"}` の `"#self"` は `"A"` と解釈されます。
`"B": {"next": "A@B@C#self"}` の `"A@B@C#self"` は `"B"` と解釈されます。1 | +| back | # の前のタスク名 | `"A@B#back"` は `"A@B"` と解釈されます。
もし直接現れた場合は `"#back"` はスキップされます。 | +| next、sub など | 前のタスク名に対応するフィールド | `next` を例に取ります。
`"A#next"` は `Task.get("A")->next` と解釈されます。
もし直接現れた場合は `"#next"` はスキップされます。 | _注1:`"XXX#self"` は `"#self"` と同じ意味を持ちます。_ @@ -333,14 +333,14 @@ default: ## 式の計算 -| 記号 | 意味 | 例 | -|:---------:|:---:|:--------:| -| `@` | テンプレートタスク | `Fight@ReturnTo` | -| `#`(単項) | 仮想タスク | `#self` | -| `#`(二項) | 仮想タスク | `StartUpThemes#next` | -| `*` | タスクの繰り返し | `(ClickCornerAfterPRTS+ClickCorner)*5` | -| `+` | タスクリストの結合(next の一連のプロパティで同じ名前を持つ最初のタスクのみが保持されます) | `A+B` | -| `^` | タスクリストの差分(前者にあり、後者にないもので、順序は変わらない) | `(A+A+B+C)^(A+B+D)` (= `C`) | +| 記号 | 意味 | 例 | +| :---------: | :-----------------------------------------------------------------------------------------: | :------------------------------------: | +| `@` | テンプレートタスク | `Fight@ReturnTo` | +| `#`(単項) | 仮想タスク | `#self` | +| `#`(二項) | 仮想タスク | `StartUpThemes#next` | +| `*` | タスクの繰り返し | `(ClickCornerAfterPRTS+ClickCorner)*5` | +| `+` | タスクリストの結合(next の一連のプロパティで同じ名前を持つ最初のタスクのみが保持されます) | `A+B` | +| `^` | タスクリストの差分(前者にあり、後者にないもので、順序は変わらない) | `(A+A+B+C)^(A+B+D)` (= `C`) | 演算子 `@`、`#`、`*`、`+`、`^` には優先順位があります: `#`(単項)> `@` = `#`(二項)> `*` > `+` = `^`。 diff --git a/docs/ja-jp/readme.md b/docs/ja-jp/readme.md index 2a75367081..6094442624 100644 --- a/docs/ja-jp/readme.md +++ b/docs/ja-jp/readme.md @@ -26,7 +26,7 @@ MAAは、MAA Assistant Arknightsです。 画像認識技術に基づいて、ワンクリックですべてのデイリーリクエストを完了します! -絶賛開発中 ✿✿ヽ(°▽°)ノ✿ +絶賛開発中 ✿✿ヽ(°▽°)ノ✿ ::: @@ -47,7 +47,7 @@ MAAは、MAA Assistant Arknightsです。 - 作業JSONファイルをインポートし、自動操作も可能! [ビデオデモ](https://www.bilibili.com/video/BV1H841177Fk/)(中文) - C、Python、Java、Rust、Golang、Java HTTP、Rust HTTPなどの多種多様なインターフェースに対応、統合や呼び出しが簡単で、自分好みにMAAをカスタマイズできます! -UIを見れば使い方もすぐ分かる! +UIを見れば使い方もすぐ分かる! -b dev - ``` + ```bash + git clone --recurse-submodules <저장소 git 링크> -b dev + ``` - ::: warning - Visual Studio 등 --recurse-submodules 미지원 Git GUI 사용 시, 클론 후 다음 실행: + ::: warning + Visual Studio 등 --recurse-submodules 미지원 Git GUI 사용 시, 클론 후 다음 실행: - ```bash - git submodule update --init - ``` + ```bash + git submodule update --init + ``` - ::: + ::: 4. 사전 빌드된 외부 라이브러리 다운로드 - **Python 환경 필요 (별도 설치 필요)** + **Python 환경 필요 (별도 설치 필요)** - ```cmd - python tools/maadeps-download.py - ``` + ```cmd + python tools/maadeps-download.py + ``` 5. 개발 환경 구성 - - - Visual Studio 2022 Community 설치 시 `C++ 데스크톱 개발` 및 `.NET 데스크톱 개발` 필수 선택 + - Visual Studio 2022 Community 설치 시 `C++ 데스크톱 개발` 및 `.NET 데스크톱 개발` 필수 선택 6. MAA.sln 파일 더블클릭 → Visual Studio에서 프로젝트 자동 로드 7. VS 설정 - - - 상단 구성에서 RelWithDebInfo x64 선택 (릴리스 빌드/ARM 플랫폼 시 생략) - - MaaWpfGui 우클릭 → 속성 → 디버그 → 네이티브 디버깅 활성화 (C++ 코어 중단점 사용 가능) + - 상단 구성에서 RelWithDebInfo x64 선택 (릴리스 빌드/ARM 플랫폼 시 생략) + - MaaWpfGui 우클릭 → 속성 → 디버그 → 네이티브 디버깅 활성화 (C++ 코어 중단점 사용 가능) 8. 이제 자유롭게 ~~개조~~ 개발 시작! 9. 주기적 커밋 (메시지 필수 작성) Git 초보자는 dev 브랜치 대신 새 브랜치 생성 권장: - ```bash - git branch your_own_branch - git checkout your_own_branch - ``` + ```bash + git branch your_own_branch + git checkout your_own_branch + ``` - dev 브랜치 업데이트 영향에서 자유로움 + dev 브랜치 업데이트 영향에서 자유로움 10. 개발 완료 후 변경사항 원격 저장소로 푸시: @@ -71,30 +69,29 @@ icon: iconoir:developer 11. [MAA 메인 저장소](https://github.com/MaaAssistantArknights/MaaAssistantArknights)에서 Pull Request 제출 (master 대신 dev 브랜치 지정 필수) 12. 업스트림 저장소 변경사항 동기화 방법: - 1. 업스트림 저장소 추가: - ```bash - git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git - ``` + ```bash + git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git + ``` 2. 변경사항 가져오기: - ```bash - git fetch upstream - ``` + ```bash + git fetch upstream + ``` 3. 리베이스(권장) 또는 병합: - ```bash - git rebase upstream/dev - ``` + ```bash + git rebase upstream/dev + ``` - 또는 + 또는 - ```bash - git merge - ``` + ```bash + git merge + ``` 4. 단계 7, 8, 9, 10 반복 수행 @@ -110,11 +107,11 @@ MAA는 리포지토리의 코드 및 리소스 파일들을 아름답고 일관 현재 활성화된 포매팅 도구는 다음과 같습니다: -| 파일 유형 | 포매팅 도구 | -| --- | --- | -| C++ | [clang-format](https://clang.llvm.org/docs/ClangFormat.html) | -| Json/Yaml | [Prettier](https://prettier.io/) | -| Markdown | [markdownlint](https://github.com/DavidAnson/markdownlint-cli2) | +| 파일 유형 | 포매팅 도구 | +| --------- | --------------------------------------------------------------- | +| C++ | [clang-format](https://clang.llvm.org/docs/ClangFormat.html) | +| Json/Yaml | [Prettier](https://prettier.io/) | +| Markdown | [markdownlint](https://github.com/DavidAnson/markdownlint-cli2) | ### Pre-commit Hooks를 사용하여 자동 포매팅을 활성화 @@ -122,10 +119,10 @@ MAA는 리포지토리의 코드 및 리소스 파일들을 아름답고 일관 2. 프로젝트 루트 디렉터리에서 다음 명령을 실행하세요. - ```bash - pip install pre-commit - pre-commit install - ``` + ```bash + pip install pre-commit + pre-commit install + ``` pip 설치 후에도 Pre-commit을 실행할 수 없다면, PIP 설치 경로가 PATH에 추가되었는지 확인하세요. @@ -135,9 +132,9 @@ pip 설치 후에도 Pre-commit을 실행할 수 없다면, PIP 설치 경로가 1. clang-format 20.1.0 또는 그 이상 버전을 설치합니다. - ```bash - python -m pip install clang-format - ``` + ```bash + python -m pip install clang-format + ``` 2. Everything 등의 도구를 사용하여 clang-format.exe의 설치 위치를 찾습니다. 참고로 Anaconda를 사용하는 경우 clang-format.exe는 YourAnacondaPath/Scripts/clang-format.exe에 설치됩니다. @@ -156,6 +153,4 @@ pip 설치 후에도 Pre-commit을 실행할 수 없다면, PIP 설치 경로가 GitHub codespace를 사용하여 자동으로 C++ 개발 환경을 구성하세요. -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights) - -그런 다음 vscode의 지침을 따르거나 [Linux 컴파일 가이드](./linux-tutorial.md)를 참고하여 GCC 12 및 CMake 프로젝트를 설정하세요. +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights?devcontainer_path=.devcontainer%2F1%2Fdevcontainer.json) diff --git a/docs/ko-kr/develop/linux-tutorial.md b/docs/ko-kr/develop/linux-tutorial.md index 4c06d39677..86ca76f7d4 100644 --- a/docs/ko-kr/develop/linux-tutorial.md +++ b/docs/ko-kr/develop/linux-tutorial.md @@ -18,7 +18,6 @@ Mac은 `tools/build_macos_universal.zsh` 스크립트를 사용하여 컴파일 ## 컴파일 과정 1. 컴파일에 필요한 종속성 다운로드 - - Ubuntu/Debian ```bash @@ -28,7 +27,6 @@ Mac은 `tools/build_macos_universal.zsh` 스크립트를 사용하여 컴파일 2. 서드파티 라이브러리 빌드 사전 빌드된 종속성 라이브러리를 다운로드하거나 직접 빌드할 수 있습니다. - - 사전 빌드된 서드파티 라이브러리 다운로드 (권장됨) > **Note** @@ -39,7 +37,6 @@ Mac은 `tools/build_macos_universal.zsh` 스크립트를 사용하여 컴파일 ``` 위의 방법으로 다운로드한 라이브러리가 시스템에서 실행되지 않거나 컨테이너와 같은 대안을 사용하지 않고 싶은 경우 직접 빌드해볼 수도 있습니다. - - 서드파티 라이브러리 직접 빌드 (시간이 오래 걸릴 수 있음) ```bash diff --git a/docs/ko-kr/develop/pr-tutorial.md b/docs/ko-kr/develop/pr-tutorial.md index f96b16de2f..a5b0d1976d 100644 --- a/docs/ko-kr/develop/pr-tutorial.md +++ b/docs/ko-kr/develop/pr-tutorial.md @@ -52,7 +52,7 @@ PR로도 알려져 있으며, "풀 리퀘스트"라는 용어는 너무 길고 물론 "요청"이니까 승인이 필요합니다. MAA 팀의 분들이 당신의 변경 사항에 대해 몇 가지 의견을 제시할 수 있습니다. 물론 우리의 의견이 모두 옳은 것은 아니며, 합리적으로 논의합니다~ -👇 아래는 현재 전문가들이 제시한 PR을 대기 중인 상태입니다. +👇 아래는 현재 전문가들이 제시한 PR을 대기 중인 상태입니다. + 2. "마스터 브랜치만" 옵션을 해제한 다음 Fork를 클릭합니다. - + 3. 이제 개인 저장소로 이동하면 제목이 "YourName/MaaAssistantArknights"이고 아래에 한 줄짜리 작은 글씨로 "forked from MaaAssistantArknights/MaaAssistantArknights" (MAA 주 저장소에서 복제됨)이라고 표시됩니다. - + 4. 수정하려는 파일을 찾아 "Go to file"을 클릭하여 전역 검색을 수행하거나 아래 폴더에서 직접 찾을 수 있습니다. (파일의 위치를 알고 있다면) - + 5. 파일을 열면 파일 오른쪽 상단의 ✏️을 클릭하여 편집합니다. - + 6. 수정하세요! (리소스 파일과 같은 경우 먼저 컴퓨터에있는 MAA 폴더에서 수정 사항을 테스트 한 다음 웹 페이지로 복사하여 잘못된 수정을 방지하세요) 7. 수정이 완료되면 맨 아래로 스크롤하여 수정 내용을 적습니다. - + - 우리는 간단한 커밋 제목 [관례적 커밋](https://www.conventionalcommits.org/zh-hans/v1.0.0/)이 있으니 가능하면 지켜주세요. 물론 정말 이해가 안 된다면 일단 아무렇게나 써도 됩니다. + 우리는 간단한 커밋 제목 [관례적 커밋](https://www.conventionalcommits.org/zh-hans/v1.0.0/)이 있으니 가능하면 지켜주세요. 물론 정말 이해가 안 된다면 일단 아무렇게나 써도 됩니다. - + 8. 두 번째 파일을 수정해야합니까? 수정 후 오류가 발생하여 수정을 다시하고 싶습니까? 전혀 문제가되지 않습니다! 5-8을 반복하세요! 9. 모두 완료되면 PR을 제출하세요! Pull Request 탭을 클릭합니다. Compare & Pull Request 버튼이 있으면 좋지만 없어도 걱정하지 마세요. 아래의 New Pull Request를 클릭하면 됩니다. (11단계 참조) - 10. 이제 주 저장소로 이동하여 제출할 PR을 확인합니다. - 아래 그림에서 화살표가 있는 곳은 오른쪽에 개인 이름/MAA의 dev 브랜치를 주 저장소/MAA의 dev 브랜치에 병합하는 것입니다. + 아래 그림에서 화살표가 있는 곳은 오른쪽에 개인 이름/MAA의 dev 브랜치를 주 저장소/MAA의 dev 브랜치에 병합하는 것입니다. + { + light: 'images/zh-cn/pr-tutorial/pr-10-1-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-10-1-dark.png' + } + ]" /> 그런 다음 제목, 수정한 내용 등을 작성하고 확인을 클릭합니다. PR 제목도 [관례적 커밋](https://www.conventionalcommits.org/zh-hans/v1.0.0/)을 지켜주세요. 물론 여전히 이해가 안 된다면 일단 아무렇게나 써도 됩니다. + { + light: 'images/zh-cn/pr-tutorial/pr-10-2-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-10-2-dark.png' + } + ]" /> 11. MAA 팀의 전문가들의 검토를 기다립니다! 물론 그들도 의견을 제시 할 수 있습니다. - 👇 예를 들어(오로지 오락을 위한 것이니 진지하게 받아들이지 마세요) + 👇 예를 들어(오로지 오락을 위한 것이니 진지하게 받아들이지 마세요) + { + light: 'images/zh-cn/pr-tutorial/pr-11-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-11-dark.png' + } + ]" /> 12. 만약 전문가들이 몇 가지 작은 문제를 수정하라고 말한다면 개인 저장소로 돌아가 이전의 dev 브랜치로 이동하여 3-9 단계를 반복하세요! - 당신의 현재 PR은 여전히 검토 대기 중이므로 나중에 수정 사항이 이 PR에 직접 반영됩니다. - 👇 예를 들어 아래에서 "재수정 데모"라는 새로운 내용이 추가된 것을 볼 수 있습니다. + 당신의 현재 PR은 여전히 검토 대기 중이므로 나중에 수정 사항이 이 PR에 직접 반영됩니다. + 👇 예를 들어 아래에서 "재수정 데모"라는 새로운 내용이 추가된 것을 볼 수 있습니다. + { + light: 'images/zh-cn/pr-tutorial/pr-12-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-12-dark.png' + } + ]" /> 13. 전문가들의 승인을 기다리면 모두 완료됩니다! 수정한 내용이 이미 MAA 메인 저장소에 들어갔습니다! diff --git a/docs/ko-kr/develop/vsc-ext-tutorial.md b/docs/ko-kr/develop/vsc-ext-tutorial.md index f65d3aab57..a0bdeac5ea 100644 --- a/docs/ko-kr/develop/vsc-ext-tutorial.md +++ b/docs/ko-kr/develop/vsc-ext-tutorial.md @@ -5,8 +5,8 @@ icon: iconoir:code-brackets # Dedicated VSCode Extension Tutorial -* [Extension Store](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) -* [Repository](https://github.com/neko-para/maa-support-extension) +- [Extension Store](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) +- [Repository](https://github.com/neko-para/maa-support-extension) ## Installation @@ -60,10 +60,10 @@ When enabling the `Maa` compatible mode, the extension will be able to recursive The extension supports scheduled scanning and diagnosing all tasks. -* Check if contains task defs with same names. -* Check if contains unknown task refs. -* Check if contains unknown image refs. -* Check if contains duplicated task refs in a single task. +- Check if contains task defs with same names. +- Check if contains unknown task refs. +- Check if contains unknown image refs. +- Check if contains duplicated task refs in a single task. #### Multiple paths resource support @@ -83,11 +83,11 @@ Searching and launching `Maa: open crop tool` inside VSCode command panel can op > Use `Ctrl+Shift+P` (`Command+Shift+P` on MacOS) to open command panel -* After selecting and connecting to the controller, use `Screencap` button to obtain screenshots -* Use `Upload` button to manually upload images. -* Hold `Ctrl` key and select cropping area -* Use wheels to zoom -* After finishing cropping, use `Download` button to save the cropping result to the folder of the topest layer of the activated resource +- After selecting and connecting to the controller, use `Screencap` button to obtain screenshots +- Use `Upload` button to manually upload images. +- Hold `Ctrl` key and select cropping area +- Use wheels to zoom +- After finishing cropping, use `Download` button to save the cropping result to the folder of the topest layer of the activated resource ### Bottom status bar diff --git a/docs/ko-kr/manual/connection.md b/docs/ko-kr/manual/connection.md index 0386b50ea9..2c4afc6735 100644 --- a/docs/ko-kr/manual/connection.md +++ b/docs/ko-kr/manual/connection.md @@ -70,7 +70,6 @@ MAA 폴더에 직접 압축을 푸는 것을 권장합니다. 그러면 ADB 경 ::: details 대체 방법 - 방법 1: adb 명령어로 에뮬레이터 포트 확인 - 1. **하나의 에뮬레이터**를 실행하고, 다른 안드로이드 장치가 이 컴퓨터에 연결되어 있지 않은지 확인합니다. 2. adb 실행 파일이 있는 폴더에서 명령어 창을 엽니다. 3. 다음 명령어를 실행합니다. @@ -93,7 +92,6 @@ MAA 폴더에 직접 압축을 푸는 것을 권장합니다. 그러면 ADB 경 `127.0.0.1:<포트>` 또는 `emulator-<네 자리 숫자>`를 연결 주소로 사용합니다. - 방법 2: 기존 adb 연결 찾기 - 1. 방법 1을 시도합니다. 2. `윈도우 키 + S`를 눌러 검색 창을 열고, `리소스 모니터`를 입력한 후 실행합니다. 3. `네트워크` 탭으로 전환하고, 수신 대기 포트의 이름 열에서 에뮬레이터 프로세스명을 찾습니다. 예: `HD-Player.exe`. @@ -138,7 +136,6 @@ MAA는 이제 레지스트리에서 `bluestacks.conf`의 저장 위치를 읽어 ::: 1. 블루스택 데이터 디렉토리에서 `bluestacks.conf` 파일을 찾습니다. - - 글로벌 버전 `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` - 중국 내륙 버전 `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` diff --git a/docs/ko-kr/manual/device/android.md b/docs/ko-kr/manual/device/android.md index 2117836801..841f3c4231 100644 --- a/docs/ko-kr/manual/device/android.md +++ b/docs/ko-kr/manual/device/android.md @@ -17,6 +17,7 @@ icon: mingcute:android-fill 3. MAA는 오직 `16:9` 비율의 해상도만 지원하므로, `16:9` 또는 `9:16` 화면 비율이 아닌 장치는 해상도를 강제로 변경해야 합니다. 이는 대부분의 현대적인 장치에 해당됩니다. 연결된 장치의 화면 비율이 원래 `16:9` 또는 `9:16`인 경우에는 해상도 변경 부분을 건너뛸 수 있습니다. 4. 잘못된 조작을 피하기 위해 기기 내비게이션 방식을 `기본 네비게이션 키` 등으로 변경하세요. 5. 게임 내 설정의 UI 위치 조절을 0으로 조정하여 작업 오류를 피하세요. + ::: ::: tip @@ -36,7 +37,6 @@ icon: mingcute:android-fill ``` - 성공적으로 실행되면 연결된 `USB 디버깅` 장치 정보가 표시됩니다. - - 예시: ```bash @@ -119,7 +119,6 @@ icon: mingcute:android-fill ``` 2. 첫 번째 파일을 `startup.bat`으로 이름을 바꾸고, 두 번째 파일을 `finish.bat`으로 이름을 바꿉니다. - - 이름을 바꾼 후 파일 아이콘이 변경되지 않고 확장명을 변경하는 이중 확인 대화 상자가 표시되지 않는 경우 "Windows에서 파일 확장명 표시하는 방법"을 검색하세요. 3. MAA의 `설정` - `연결 설정` - `시작 전 스크립트` 및 `종료 후 스크립트`에 각각 `startup.bat`과 `finish.bat`을 입력합니다. @@ -150,7 +149,6 @@ icon: mingcute:android-fill ``` 2. 장치 IP 주소를 확인합니다. - - 장치의 `설정` - `WLAN`으로 이동하여 현재 연결된 무선 네트워크를 클릭하여 IP 주소를 확인합니다. - 각 브랜드의 장치는 설정 위치가 다를 수 있으므로 검색하여 찾으세요. @@ -166,7 +164,6 @@ icon: mingcute:android-fill 1. 휴대폰의 개발자 옵션으로 이동하여 `무선 디버깅`을 클릭하여 활성화하고 확인을 클릭한 후 `페어링 코드로 디바이스 페어링`을 클릭하고 페어링이 완료될 때까지 나타나는 팝업을 닫지 마세요. 2. 페어링을 시작합니다. - 1. 명령 프롬프트에서 `adb pair <장치에 표시된 IP 주소와 포트>`를 입력하고 엔터를 누릅니다.。 2. `<장치에 표시된 6자리 페어링 코드>`를 입력하고 엔터를 누릅니다. 3. 창에 `Successfully paired to `와 같은 내용이 나타나면서 장치에서 팝업이 자동으로 닫히고 페어링된 장치 아래에 컴퓨터 이름이 표시됩니다. diff --git a/docs/ko-kr/manual/device/linux.md b/docs/ko-kr/manual/device/linux.md index 0e2bdc25b9..b279b71b90 100644 --- a/docs/ko-kr/manual/device/linux.md +++ b/docs/ko-kr/manual/device/linux.md @@ -59,7 +59,6 @@ MAA Wine Bridge에서 생성된 `MaaDesktopIntegration.so`를 `MAA.exe`와 같 #### 1. MAA 동적 라이브러리 설치 1. [MAA 공식 웹사이트](https://maa.plus/)에서 리눅스 라이브러리를 다운로드하고 압축을 풉니다. 혹은 소프트웨어 저장소에서 설치합니다: - - AUR:[maa-assistant-arknights](https://aur.archlinux.org/packages/maa-assistant-arknights)을 설치한 후에 설치 지침에 따라 파일을 편집합니다. - Nixpkgs: [maa-assistant-arknights](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-assistant-arknights/package.nix) @@ -74,7 +73,6 @@ MAA Wine Bridge에서 생성된 `MaaDesktopIntegration.so`를 `MAA.exe`와 같 1. [`if asst.connect('adb.exe', '127.0.0.1:5554'):`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/722f0ddd4765715199a5dc90ea1bec2940322344/src/Python/sample.py#L48) 줄을 찾습니다. 2. `adb` 도구 호출 - - 에뮬레이터가 `Android Studio`의 `avd`를 사용하는 경우 `adb`가 내장되어 있습니다. `adb.exe` 필드에 `adb` 경로를 입력합니다. 일반적으로 `$HOME/Android/Sdk/platform-tools/` 폴더에 있습니다. 예시: ```python @@ -84,7 +82,6 @@ MAA Wine Bridge에서 생성된 `MaaDesktopIntegration.so`를 `MAA.exe`와 같 - 다른 에뮬레이터를 사용하는 경우 `adb`를 먼저 다운로드해야 합니다: `$ sudo apt install adb`를 실행한 후 경로를 입력하거나 `PATH` 환경 변수를 사용하여 `adb`를 입력합니다. 3. 에뮬레이터의 `adb` 경로 확인: - - 직접 `adb` 도구를 사용할 수 있습니다: `$ adb경로 devices`를 실행하면 됩니다. 예시: ```shell diff --git a/docs/ko-kr/manual/faq.md b/docs/ko-kr/manual/faq.md index 8d10bb6e09..fc7fa27d57 100644 --- a/docs/ko-kr/manual/faq.md +++ b/docs/ko-kr/manual/faq.md @@ -49,8 +49,8 @@ Windows 7의 경우, 위에서 언급한 두 개의 런타임 라이브러리를 1. [Windows 7 Service Pack 1](https://support.microsoft.com/zh-cn/windows/b3da2c0f-cdb6-0572-8596-bab972897f61) 2. SHA-2 코드 서명 패치: - - KB4474419:[다운로드 링크 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)、[다운로드 링크 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu) - - KB4490628:[다운로드 링크 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)、[다운로드 링크 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu) + - KB4474419:[다운로드 링크 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)、[다운로드 링크 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu) + - KB4490628:[다운로드 링크 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)、[다운로드 링크 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):[다운로드 링크 1](https://catalog.s.download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu)、[다운로드 링크 2](http://download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu) ##### .NET 8 애플리케이션이 Windows 7에서 비정상적으로 실행되는 문제 완화 조치 [#8238](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/8238) @@ -94,7 +94,7 @@ Windows 7에서 .NET 8 애플리케이션을 실행할 때 메모리 사용량 | 에뮬레이터 | 포트 기본값 | | ---------- | :------------------: | | MuMu 6/X | 7555 | -| MuMu | 16384 | +| MuMu | 16384 | | NoxPlayer | 62001 | | Memu | 21503 | | BlueStacks | 5555 | @@ -107,7 +107,7 @@ Windows 7에서 .NET 8 애플리케이션을 실행할 때 메모리 사용량 ### 기존 adb 프로세스 종료 MAA를 종료한 후 작업 관리자에서 `세부 정보`에서 `adb`라는 이름을 포함한 프로세스가 있는지 확인하세요.있다면 종료한 후 다시 연결을 시도하세요. - (일반적으로 앞서 입력한 adb 파일과 동일한 이름을 갖습니다) +(일반적으로 앞서 입력한 adb 파일과 동일한 이름을 갖습니다) ### 여러 adb를 올바르게 사용하기 @@ -173,7 +173,6 @@ MAA는 이제 레지스트리에서 `bluestacks.conf`의 위치를 읽으려고 ::: 1. 블루스택 에뮬레이터 데이터 디렉터리에서 `bluestacks.conf` 파일을 찾으세요. - - 국제 버전의 기본 경로는 `C:\ProgramData\BlueStacks_nxt\bluestacks.conf`입니다. - 중국 본토 버전의 기본 경로는 `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf`입니다. diff --git a/docs/ko-kr/manual/introduction/combat.md b/docs/ko-kr/manual/introduction/combat.md index 00de656155..9f200afa52 100644 --- a/docs/ko-kr/manual/introduction/combat.md +++ b/docs/ko-kr/manual/introduction/combat.md @@ -8,7 +8,6 @@ icon: hugeicons:brain-02 ## 일반 설정 - `이성 사용`의 일반 설정에있는 `이성 회복제 사용 + 순오리지늄 사용`과 `횟수 제한` 및 `드롭 제한` 세 가지 옵션은 하나만 만족해도 종료가 됩니다. - - `이성 회복제 사용` 은 특정 횟수의 이성 회복제를 사용해 이성을 회복합니다. (연속으로 이성 회복제 사용이 가능합니다) - `순오리지늄` 은 특정 횟수의 순오리지늄을 사용하며, 이성 회복제가 남아있을 경우 사용되지 않습니다. - `횟수 제한` 은 선택한 스테이지를 몇번 클리어 할 지 정합니다. (예시: 15번 클리어 후 정지) @@ -19,26 +18,26 @@ icon: hugeicons:brain-02 ::: details 예시 -| 이성 회복제 | 순오리지늄 | 횟수 제한 | 드롭 제한 | 결과 | +| 이성 회복제 | 순오리지늄 | 횟수 제한 | 드롭 제한 | 결과 | | :---------: | :--------: | :-------: | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| | | | | 보유한 이성을 소모하고 정지합니다. | -| 2 | | | | 현재 이성을 소모한 후, 이성 회복제를 `2`회 소모하고 정지합니다. | -| _999_ | 2 | | | 현재 이성을 소모한 후, 이성 회복제를 소모하고, 순오리지늄을 `2`회 사용 후 정지합니다. | -| | | 2 | | 지정한 스테이지를 `2`회 반복하고 정지합니다. | -| | | | 2 | 특정 재화를 `2`개 획득하면 정지합니다. | -| 2 | | 4 | | 작전을 `4`회 시도하며, 이성이 부족하면 최대 `2`개의 이성 회복제를 사용합니다. | -| 2 | | | 4 | 특정 재화를 `4`개 획득하면 정지하며, 이성이 부족하면 최대 `2`개의 이성 회복제를 사용합니다. | -| 2 | | 4 | 8 | 작전을 `4`회 시도하며, 작전이 전부 끝나기전에 재화를 `8`개를 획득하면 정지합니다. 이성이 부족하면 최대 `2`개의 이성 회복제를 사용합니다. | -| _999_ | 4 | 8 | 16 | 모든 이성 회복제를 사용하며, `4`개의 순오리지늄을 사용합니다. 단, `8`회의 작전을 끝내면 정지하며, 그 이전에 `16`개의 재화를 획득하면 정지합니다. | -| | 2 | | | `2`개의 순오리지늄을 사용하며, 이성을 전부 소모하면 정지합니다. | -| 2 | 4 | | | `2`개의 이성 회복제를 사용하며, 이후 `4`개의 순오리지늄을 사용합니다. 이성을 전부 소모하면 정지합니다. | +| | | | | 보유한 이성을 소모하고 정지합니다. | +| 2 | | | | 현재 이성을 소모한 후, 이성 회복제를 `2`회 소모하고 정지합니다. | +| _999_ | 2 | | | 현재 이성을 소모한 후, 이성 회복제를 소모하고, 순오리지늄을 `2`회 사용 후 정지합니다. | +| | | 2 | | 지정한 스테이지를 `2`회 반복하고 정지합니다. | +| | | | 2 | 특정 재화를 `2`개 획득하면 정지합니다. | +| 2 | | 4 | | 작전을 `4`회 시도하며, 이성이 부족하면 최대 `2`개의 이성 회복제를 사용합니다. | +| 2 | | | 4 | 특정 재화를 `4`개 획득하면 정지하며, 이성이 부족하면 최대 `2`개의 이성 회복제를 사용합니다. | +| 2 | | 4 | 8 | 작전을 `4`회 시도하며, 작전이 전부 끝나기전에 재화를 `8`개를 획득하면 정지합니다. 이성이 부족하면 최대 `2`개의 이성 회복제를 사용합니다. | +| _999_ | 4 | 8 | 16 | 모든 이성 회복제를 사용하며, `4`개의 순오리지늄을 사용합니다. 단, `8`회의 작전을 끝내면 정지하며, 그 이전에 `16`개의 재화를 획득하면 정지합니다. | +| | 2 | | | `2`개의 순오리지늄을 사용하며, 이성을 전부 소모하면 정지합니다. | +| 2 | 4 | | | `2`개의 이성 회복제를 사용하며, 이후 `4`개의 순오리지늄을 사용합니다. 이성을 전부 소모하면 정지합니다. | ::: ### 작전 개시 (이성 사용) - 만약 여러분이 원하는 스테이지가 목록에 없다면 MAA에서 `현재/최근`을 선택한 다음 게임 내에서 수동으로 스테이지를 찾으세요. -스테이지 이름, 정보, 소모 이성이 뜨고 오른쪽 하단에 대리지휘와 시작 버튼이 표시된 화면으로 가세요. + 스테이지 이름, 정보, 소모 이성이 뜨고 오른쪽 하단에 대리지휘와 시작 버튼이 표시된 화면으로 가세요. - 해당 화면이 아닌 경우 `현재/이전`은 자동으로 가장 최근에 실행한 스테이지로 이동합니다. - 또는 작업 `설정` - `이성 사용` - `고급 설정`에서 `스테이지 코드 수동 입력`을 체크해 스테이지 코드를 직접 입력할 수 있습니다. 현재 내비게이션할 수 있는 스테이지는 다음과 같습니다: - 모든 메인 스토리 스테이지. 표준 또는 어려움 난이도를 전환하려면 스테이지 코드 뒤에 -NORMAL 또는 -HARD를 추가하세요. @@ -46,7 +45,6 @@ icon: hugeicons:brain-02 - 스킬 북, 구매 증명서, 카본 부품 5스테이지는 `CA-5`/`AP-5`/`SK-5`를 입력해야 합니다. - 모든 칩 스테이지. 완전한 스테이지 코드를 입력해야 합니다. 예: `PR-A-1`. - 섬멸 모드는 다음 값을 지원합니다: - - 이번 섬멸 작전:Annihilation - 체르노보그:Chernobog@Annihilation - 용문 외곽:LungmenOutskirts@Annihilation @@ -86,7 +84,7 @@ icon: hugeicons:brain-02 `이성 사용`이 종료된 후에 시작되며, 이성 회복제 사용, 순오리지늄 사용, 횟수 제한, 드롭 제한, 연속 전투 횟수 등의 제어를 받지 않고, 이성을 모두 소비하면 종료됩니다. - 스테이지 개시 시 이성이 부족한 경우, 남은 이성 스테이지로 이동하여 "나머지" 이성을 소모합니다. (예: 1-7) -- 이성이 부족하여 연속 전투 횟수가 너무 높게 설정된 경우에도 자동으로 단일 전투 횟수로 선택되어 이성을 모두 소비합니다(예: 1-7을 6회 연속 전투 설정하지만, 이성이 30밖에 되지 않는 경우, 자동으로 연속 전투 없는 1-7로 전환됩니다). +- 이성이 부족하여 연속 전투 횟수가 너무 높게 설정된 경우에도 자동으로 단일 전투 횟수로 선택되어 이성을 모두 소비합니다(예: 1-7을 6회 연속 전투 설정하지만, 이성이 30밖에 되지 않는 경우, 자동으로 연속 전투 없는 1-7로 전환됩니다). - 여전히 이성이 부족하면 작업을 중지합니다.(예: 6 이하의 이성) - 남은 이성 선택 스테이지가 개방되지 않은 스테이지인 경우, 이성 사용에 실패합니다. @@ -114,7 +112,7 @@ MAA는 지정된 횟수만큼 전투를 수행합니다. - 지정된 횟수가 10으로 설정되고 대리 배율이 4로 설정된 경우: 2(시작 행동) x 4(대리 배율) = 8번의 작업이 수행되며(2 x 플로어(10 / 4) = 8), 8 x 6 = 48의 이성이 소모됩니다. 이때, 4배 프록시를 다시 실행하면 12회 작업이 발생하여 설정된 10회를 초과하므로 더 이상 실행되지 않고, 미션은 8회 작업으로 종료됩니다. -- 지정된 횟수는 10회로 설정되고, 프록시 배수는 AUTO로 설정됩니다. 6배 프록시 1회 + 4배 프록시 1회 = 10회 작업이 실행됩니다(6 * floor(10 / 6) + (10 % 6) = 10). 따라서 10 x 6 = 60의 이성이 소모됩니다. +- 지정된 횟수는 10회로 설정되고, 프록시 배수는 AUTO로 설정됩니다. 6배 프록시 1회 + 4배 프록시 1회 = 10회 작업이 실행됩니다(6 \* floor(10 / 6) + (10 % 6) = 10). 따라서 10 x 6 = 60의 이성이 소모됩니다. ### 드롭 인식 diff --git a/docs/ko-kr/manual/introduction/infrastructure.md b/docs/ko-kr/manual/introduction/infrastructure.md index 89d851badc..023751d07c 100644 --- a/docs/ko-kr/manual/introduction/infrastructure.md +++ b/docs/ko-kr/manual/introduction/infrastructure.md @@ -33,4 +33,4 @@ icon: material-symbols:view-quilt-rounded ## 커스텀 기반시설 - MAA 폴더의 `/resource/custom_infrast/`에는 이론적 최대 효율의 작업 몇 개가 내장되어 있습니다. 오퍼레이터 인원 수 및 육성의 요구 사항이 매우 높기 때문에 직접 사용하는 것은 권장하지 않습니다. -- Yituliu의 JSON 생성기를 참고해서 작성하세요. [기반시설 JSON 생성기](https://ark.yituliu.cn/tools/schedule), [기반시설 프로토콜 문서](../../protocol/base-scheduling-schema.md)도 참조하세요. +- Yituliu의 JSON 생성기를 참고해서 작성하세요. [기반시설 JSON 생성기](https://ark.yituliu.cn/tools/schedule), [기반시설 프로토콜 문서](../../protocol/base-scheduling-schema.md)도 참조하세요. diff --git a/docs/ko-kr/manual/introduction/others.md b/docs/ko-kr/manual/introduction/others.md index 3ede6f9310..c6bb82fbe8 100644 --- a/docs/ko-kr/manual/introduction/others.md +++ b/docs/ko-kr/manual/introduction/others.md @@ -34,7 +34,7 @@ v4.13.0 이후에는 시작 전/후 스크립트를 설정할 수 있으며, 작 ## 참고 - UI에서 작업 순서를 변경할 수 있습니다. 인프라에서도 이동 순서를 변경할 수 있습니다. --거의 모든 구성 변경은 자동으로 저장됩니다. `*`, `(only once)` 및 우클릭으로 반 선택하는 옵션은 예외입니다. +- 거의 모든 구성 변경은 자동으로 저장됩니다. `*`, `(only once)` 및 우클릭으로 반 선택하는 옵션은 예외입니다. - 모든 클릭 이벤트는 해당 지역 내에서 랜덤하게 발생하며, 포아송 분포를 따릅니다. (중심 부근에서 높은 확률, 주변에서 낮은 확률) - C++로 개발되었으며, 핵심 알고리즘은 CPU 및 메모리 사용량을 최소화하기 위해 다단계 캐시를 지원합니다. - 소프트웨어는 자동 업데이트를 지원합니다 ✿✿ ヽ(°▽°)ノ ✿ 베타 테스터들은 더 빠르고 덜 버그가 있는 베타 버전을 시도할 수 있습니다 (아마도). diff --git a/docs/ko-kr/manual/introduction/tools.md b/docs/ko-kr/manual/introduction/tools.md index c3d80037d5..fcece40b0d 100644 --- a/docs/ko-kr/manual/introduction/tools.md +++ b/docs/ko-kr/manual/introduction/tools.md @@ -27,7 +27,7 @@ JSON 스키마와 통합을 희망하는 경우 언제든지 문의해주세요. ## 영상 인식 (Alpha) -전술 비디오를 인식하고 자동으로 Copilot 파일을 생성할 수 있습니다. 비디오 파일을 Copilot 탭 페이지로 끌어다 놓으면 시작됩니다. +전술 비디오를 인식하고 자동으로 Copilot 파일을 생성할 수 있습니다. 비디오 파일을 Copilot 탭 페이지로 끌어다 놓으면 시작됩니다. 가로세로 비율이 16:9 이고 720p 이상의 해상도를 갖는 비디오만 지원됩니다. 비디오 내용에는 검은 테두리, 왜곡 보정, 에뮬레이터 테두리 또는 기타 요소가 없어야 합니다. diff --git a/docs/ko-kr/manual/newbie.md b/docs/ko-kr/manual/newbie.md index e338a17924..18b54829c4 100644 --- a/docs/ko-kr/manual/newbie.md +++ b/docs/ko-kr/manual/newbie.md @@ -11,31 +11,31 @@ icon: ri:guide-fill 1. 시스템 버전 확인 - MAA 는 Windows 10/11만 지원합니다. 이전 버전의 Windows를 사용하는 경우 [FAQ](./faq.md#가능성2:런타임문제)를 참조하세요. + MAA 는 Windows 10/11만 지원합니다. 이전 버전의 Windows를 사용하는 경우 [FAQ](./faq.md#가능성2:런타임문제)를 참조하세요. - Windows 사용자가 아닌 경우 [에뮬레이터 및 장치 지원](./device/)을 참조하십시오. + Windows 사용자가 아닌 경우 [에뮬레이터 및 장치 지원](./device/)을 참조하십시오. 2. 알맞는 버전 다운로드 - [MAA 홈페이지](https://maa.plus/)는 일반적으로 알맞는 버전 아키텍처를 자동으로 선택합니다. 대부분의 사용자에게는 Windows x64가 해당됩니다. + [MAA 홈페이지](https://maa.plus/)는 일반적으로 알맞는 버전 아키텍처를 자동으로 선택합니다. 대부분의 사용자에게는 Windows x64가 해당됩니다. 3. 알맞는 압축 해제 - 압축 해제가 완료되었는지 확인하고, MAA를 독립된 폴더에 압축 해제하세요. `C:\`, `C:\Program Files\`와 같이 UAC 권한이 필요한 경로에는 압축을 해제하지 마세요. + 압축 해제가 완료되었는지 확인하고, MAA를 독립된 폴더에 압축 해제하세요. `C:\`, `C:\Program Files\`와 같이 UAC 권한이 필요한 경로에는 압축을 해제하지 마세요. 4. 런타임 설치 - MAA는 VCRedist x64 및 .NET 8이 필요합니다. MAA 디렉토리의 `DependencySetup_依赖库安装.bat`를 실행하여 설치하세요. + MAA는 VCRedist x64 및 .NET 8이 필요합니다. MAA 디렉토리의 `DependencySetup_依赖库安装.bat`를 실행하여 설치하세요. - 자세한 정보는 [FAQ](./faq.md#가능성-2-런타임-문제)를 참조하세요. + 자세한 정보는 [FAQ](./faq.md#가능성-2-런타임-문제)를 참조하세요. 5. 에뮬레이터 지원 확인 - [에뮬레이터 및 지원 장치](./device/)를 참조하여 사용 중인 에뮬레이터가 지원되는지 확인하세요. + [에뮬레이터 및 지원 장치](./device/)를 참조하여 사용 중인 에뮬레이터가 지원되는지 확인하세요. 6. 에뮬레이터 해상도 설정 - 에뮬레이터 해상도는 가로 모드에서 `1280x720` 또는 `1920x1080`이어야 합니다. YosterEN 플레이어의 경우 `1920x1080`이어야 합니다. + 에뮬레이터 해상도는 가로 모드에서 `1280x720` 또는 `1920x1080`이어야 합니다. YosterEN 플레이어의 경우 `1920x1080`이어야 합니다. ## 초기 설정 diff --git a/docs/ko-kr/protocol/callback-schema.md b/docs/ko-kr/protocol/callback-schema.md index 1a3b470809..8ef2ed9630 100644 --- a/docs/ko-kr/protocol/callback-schema.md +++ b/docs/ko-kr/protocol/callback-schema.md @@ -199,7 +199,7 @@ typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom #### 자주 사용되는 `subtask` 필드 값 -- `ProcessTask` +- `ProcessTask` ```json // 상세 정보에 대한 예시 @@ -448,14 +448,14 @@ typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom ``` - `RecruitNoPermit` - 모집 라이센스가 없습니다 + 모집 라이센스가 없습니다 - ```json - // 상세 정보에 대한 예시 - { - "continue": true, // 계속 새로고침할지 말지 - } - ``` + ```json + // 상세 정보에 대한 예시 + { + "continue": true, // 계속 새로고침할지 말지 + } + ``` - `RecruitTagsSelected` 공개모집 태그 선택 완료 diff --git a/docs/ko-kr/protocol/integrated-strategy-schema.md b/docs/ko-kr/protocol/integrated-strategy-schema.md index 178ed19334..f4e0032189 100644 --- a/docs/ko-kr/protocol/integrated-strategy-schema.md +++ b/docs/ko-kr/protocol/integrated-strategy-schema.md @@ -49,7 +49,7 @@ icon: ri:game-fill ### 오퍼레이터 분류 -게임 이해에 따라 오퍼레이터를 다양한 ***groups*** (관련 개념은 [전투 스키마](./copilot-schema.md)를 참고)으로 분류합니다 +게임 이해에 따라 오퍼레이터를 다양한 **_groups_** (관련 개념은 [전투 스키마](./copilot-schema.md)를 참고)으로 분류합니다 ::: info 주의 @@ -60,6 +60,7 @@ icon: ri:game-fill 3. 기존의 그룹 이름을 수정하지 마세요. MAA 업데이트 시 이전 버전의 작업을 사용할 수 없게 될 수 있습니다. 4. 새로운 그룹을 가능한 한 추가하지 마시고, 새로 추가하는 단위를 기존 그룹에 편입시키세요. + ::: ::: tip @@ -93,33 +94,33 @@ icon: ri:game-fill 1. 기존 그룹 소개 - 팬텀의 로그라이크를 예로 들어 설명: 오퍼레이터는 주로 다음과 같이 분류됩니다. + 팬텀의 로그라이크를 예로 들어 설명: 오퍼레이터는 주로 다음과 같이 분류됩니다. - | Group | Considerations | Class | Operators | - | :------------------------ | :------------------- | :--------------- | :----------------------------------------------------------------- | - | ***Ground block*** | 전장과 잡몹 정리 | 디펜더, 가드 | 라 플루마, 마운틴, 몬3터, 링과 씬의 소환물, 스팟, 디펜더 예비 인원 | - | ***Ground single-block*** | 단독으로 보스와 교전 | 처형자, 스페셜 | 수르트, 키린R 야토, 몬3터, 레드 | - | ***Ranged C*** | 일반과 결전 | 스나이퍼, 캐스터 | 첸 더 홀룽데이, 골든글로우, 에이야퍄들라, 피아메타 | - | ***Ranged DPS*** | 대공 및 일반 | 스나이퍼, 캐스터 | 아르케토, 엑시아, 크루스, 스튜어드 | - | ***힐러*** | 치료 능력 | 힐러, 서포터 | 켈시, 스카디 더 커럽팅 하트, 히비스커스, 안셀 | - | ***코스트 회복*** | 코스트 회복 | 뱅가드 | 머틀, 이네스, 팽, 바닐라 | - | ***포탄 흡수*** | 포탄 흡수, 재배치 | 특수, 소환물 | 몬3터, 레드, 머틀, 예비 인원 | - | ***고지대 예비*** | 일정한 공격 능력 | | 오키드, 예비 인원 | + | Group | Considerations | Class | Operators | + | :------------------------ | :------------------- | :--------------- | :----------------------------------------------------------------- | + | **_Ground block_** | 전장과 잡몹 정리 | 디펜더, 가드 | 라 플루마, 마운틴, 몬3터, 링과 씬의 소환물, 스팟, 디펜더 예비 인원 | + | **_Ground single-block_** | 단독으로 보스와 교전 | 처형자, 스페셜 | 수르트, 키린R 야토, 몬3터, 레드 | + | **_Ranged C_** | 일반과 결전 | 스나이퍼, 캐스터 | 첸 더 홀룽데이, 골든글로우, 에이야퍄들라, 피아메타 | + | **_Ranged DPS_** | 대공 및 일반 | 스나이퍼, 캐스터 | 아르케토, 엑시아, 크루스, 스튜어드 | + | **_힐러_** | 치료 능력 | 힐러, 서포터 | 켈시, 스카디 더 커럽팅 하트, 히비스커스, 안셀 | + | **_코스트 회복_** | 코스트 회복 | 뱅가드 | 머틀, 이네스, 팽, 바닐라 | + | **_포탄 흡수_** | 포탄 흡수, 재배치 | 특수, 소환물 | 몬3터, 레드, 머틀, 예비 인원 | + | **_고지대 예비_** | 일정한 공격 능력 | | 오키드, 예비 인원 | 2. 특별 취급이 필요한 그룹 - 위의 일반적인 그룹 외에도 일부 오퍼레이터나 유형에 대한 맞춤형 조정이 필요할 수 있습니다. + 위의 일반적인 그룹 외에도 일부 오퍼레이터나 유형에 대한 맞춤형 조정이 필요할 수 있습니다. - | Group | Operators | Features | - | :---------- | :-------------------- | :--------------------------------------------------------------------------------------------------- | - | Thorns | 쏜즈, 혼 | 장거리 근접, 많은 맵에서 좋음 | - | Summoners | 켈시, 링, 씬 | 근접 블록, 일부 맵은 배치 우선순위 필요, 소환물은 블록 또는 포드로 사용 가능 | - | Agent | 칸타빌레, 이네스 | 코스트 회복 가능, DPS 제공 및 단일 블록 | - | Skadi Alter | 스카디 더 커럽팅 하트 | 낮은 DP 비용, 특별한 범위, 일부 맵에서 최적의 위치 | - | Reed Alter | 리드 더 플레임 섀도우 | 사미 로그라이크에서 개막 캐스터, DPS 및 치유로 자주 사용, 일부 맵에서 최적의 위치 | - | SilverAsh | 실버애쉬, 무에나 | 큰 범위의 지상 오퍼레이터, 보스에게 매우 유용 | - | Surtr | 수르트 | 수르트는 항상 세 번째 스킬을 사용하므로 위치 선정 능력이 거의 없으며, 배치 우선순위가 매우 낮습니다. | - | Dice | 주사위 | 미즈키 로그라이크에서 주사위는 별도로 작동해야 합니다. | + | Group | Operators | Features | + | :---------- | :-------------------- | :--------------------------------------------------------------------------------------------------- | + | Thorns | 쏜즈, 혼 | 장거리 근접, 많은 맵에서 좋음 | + | Summoners | 켈시, 링, 씬 | 근접 블록, 일부 맵은 배치 우선순위 필요, 소환물은 블록 또는 포드로 사용 가능 | + | Agent | 칸타빌레, 이네스 | 코스트 회복 가능, DPS 제공 및 단일 블록 | + | Skadi Alter | 스카디 더 커럽팅 하트 | 낮은 DP 비용, 특별한 범위, 일부 맵에서 최적의 위치 | + | Reed Alter | 리드 더 플레임 섀도우 | 사미 로그라이크에서 개막 캐스터, DPS 및 치유로 자주 사용, 일부 맵에서 최적의 위치 | + | SilverAsh | 실버애쉬, 무에나 | 큰 범위의 지상 오퍼레이터, 보스에게 매우 유용 | + | Surtr | 수르트 | 수르트는 항상 세 번째 스킬을 사용하므로 위치 선정 능력이 거의 없으며, 배치 우선순위가 매우 낮습니다. | + | Dice | 주사위 | 미즈키 로그라이크에서 주사위는 별도로 작동해야 합니다. | ::: info 현재 정해진 그룹을 알 수 없는 지상 크루는 마지막 전형 (다른 지상) 뒤에, 고지대 그룹는 마지막 전형 (다른 고지대) 뒤에 고정되어 있습니다. @@ -169,7 +170,7 @@ icon: ri:game-fill ```json { - "theme": "Phantom", + "theme": "Phantom", "priority": [ "name": "GroundBlocking", // 그룹 이름 (이 경우 GroundBlocking) "doc": "기준 라인은 1단 기어 (청소 능력 또는 필드 능력이 산보다 우수) > 산 > 2단 기어 (블록>2, 자체 회복 가능) > Spot, 필드 능력이 Spot보다 적은 경우 단일 절단 또는 포드 그룹", @@ -200,11 +201,11 @@ icon: ri:game-fill // 시작 오퍼레이터과 0 희망 오퍼레이터만 모집하고, 사용자로부터 작성된 오퍼레이터을 모집합니다. "auto_retreat": 0, // 배치 후 몇 초 동안 자동 후퇴, 0보다 큰 경우 유효, 주로 특수 오퍼레이터 및 전위에 사용, // 로그라이크는 보통 2배 속도로 시작하므로 스킬 지속 시간을 2로 나누는 것이 좋습니다. - "promote_priority_when_team_full": 850, + "promote_priority_when_team_full": 850, "recruit_priority_offsets": [ // 현재 라인업에 따라 우선순위 조정 { "groups": [ // 조건을 충족해야 하는 그룹 - "Kaltsit", + "Kaltsit", "GroundBlocking", "Thorns" ], @@ -219,7 +220,7 @@ icon: ri:game-fill ... ], ], - "team_complete_condition": [ + "team_complete_condition": [ ... ] } @@ -227,7 +228,7 @@ icon: ri:game-fill 3. 그룹과 오퍼레이터를 필요에 따라 추가합니다. - 새로운 그룹을 추가할 때 기존 그룹에서 오퍼레이터를 복사할 수 있습니다. 개발자가 이미 부여한 평가를 참고하고, 이를 바탕으로 수정합니다. + 새로운 그룹을 추가할 때 기존 그룹에서 오퍼레이터를 복사할 수 있습니다. 개발자가 이미 부여한 평가를 참고하고, 이를 바탕으로 수정합니다. ## 통합 전략 2단계 - 전투 로직 @@ -236,88 +237,86 @@ icon: ri:game-fill ### MAA의 기본 로그라이크 전투 로직 1. 맵의 그리드 유형에 따라 기본 전투 작업 수행 + - MAA는 맵의 그리드가 목표 지점인지 적 출현 지점인지, 고지대인지 지상인지, 배치 가능한지 여부에 따라 기본 전투 작업을 수행합니다. - - MAA는 맵의 그리드가 목표 지점인지 적 출현 지점인지, 고지대인지 지상인지, 배치 가능한지 여부에 따라 기본 전투 작업을 수행합니다. + - MAA는 맵 이름이나 번호를 기준으로 직업을 결정하며, 맵의 **표준**, **긴급**, **분기점**, **아이템 사용** 등의 상황을 판단하지 않습니다. - - MAA는 맵 이름이나 번호를 기준으로 직업을 결정하며, 맵의 **표준**, **긴급**, **분기점**, **아이템 사용** 등의 상황을 판단하지 않습니다. - - - MAA는 전투 중 **맵의 정의되지 않은 그리드**을 판단하지 않습니다. 예를 들어, `Taming Hut`의 제단 위치, 왼쪽이나 오른쪽에서 나오는 몬스터의 `팔로워 효과` 등을 판단하지 않습니다. + - MAA는 전투 중 **맵의 정의되지 않은 그리드**을 판단하지 않습니다. 예를 들어, `Taming Hut`의 제단 위치, 왼쪽이나 오른쪽에서 나오는 몬스터의 `팔로워 효과` 등을 판단하지 않습니다. 따라서 미래에는 **맵 이름의 모든 시나리오**에 대응할 수 있는 전투 로직을 설계해야 하며, 이 맵이 긴급 모드에서 작동하는 문제에 주의해야 합니다. 2. MAA의 기본 전투 전략 -- 목표 지점 진입 막기 + 1. 지상 크루는 우선적으로 목표 지점 (그리드)를 중심으로 (또는 주변) 배치되며, 적 출현 지점을 향해 배치됩니다 (자동으로 계산됨). 적 출현 지점에는 배치되지 않습니다. - 1. 지상 크루는 우선적으로 목표 지점 (그리드)를 중심으로 (또는 주변) 배치되며, 적 출현 지점을 향해 배치됩니다 (자동으로 계산됨). 적 출현 지점에는 배치되지 않습니다. + 2. 고지대보다 지상을 우선 배치하고, 목표 지점에서 주변으로 원형으로 배치됩니다. - 2. 고지대보다 지상을 우선 배치하고, 목표 지점에서 주변으로 원형으로 배치됩니다. - - 3. 위의 로직에 따라 배치할 수 있는 것들 (오퍼레이터, 소환물, 지원 아이템 등)을 계속 배치합니다. + 3. 위의 로직에 따라 배치할 수 있는 것들 (오퍼레이터, 소환물, 지원 아이템 등)을 계속 배치합니다. ### 기본 전투 전략 최적화 1. 목표 지점 대체 - 목표 지점 앞에 오퍼레이터를 쌓는 것은 분명히 현명하지 않습니다. 일부 레벨에는 통과할 수 없는 그리드가 있으며, 이러한 위치에서는 방어가 매우 효율적입니다. + 목표 지점 앞에 오퍼레이터를 쌓는 것은 분명히 현명하지 않습니다. 일부 레벨에는 통과할 수 없는 그리드가 있으며, 이러한 위치에서는 방어가 매우 효율적입니다. - 또는 여러 목표 지점이 있는 레벨에서 MAA가 어떤 목표 지점가 어떤 적 출현 지점와 대응되는지 모를 경우, 무작위로 배치할 수 있습니다. + 또는 여러 목표 지점이 있는 레벨에서 MAA가 어떤 목표 지점가 어떤 적 출현 지점와 대응되는지 모를 경우, 무작위로 배치할 수 있습니다. - 이 경우 [map wiki](https://map.ark-nights.com/areas?coord_override=maa)를 열고 전투를 상상하면서 방어해야 할 우선순위 그리드와 방향을 찾아 `replacement_home`에 작성합니다. + 이 경우 [map wiki](https://map.ark-nights.com/areas?coord_override=maa)를 열고 전투를 상상하면서 방어해야 할 우선순위 그리드와 방향을 찾아 `replacement_home`에 작성합니다. - 이 링크를 사용하세요. 그렇지 않으면 `설정`에서 `좌표 표시`를 `MAA`로 전환하세요. + 이 링크를 사용하세요. 그렇지 않으면 `설정`에서 `좌표 표시`를 `MAA`로 전환하세요. - 그런 다음, 경험을 바탕으로 방어 우선순위가 필요한 지점의 좌표와 방향을 찾아 json의 `replacement_home`에 작성하세요. + 그런 다음, 경험을 바탕으로 방어 우선순위가 필요한 지점의 좌표와 방향을 찾아 json의 `replacement_home`에 작성하세요. - ```json - { - "stage_name": "蓄水池", // 레벨 이름 (중국어) - "replacement_home": [ // 진입 지점 (목표 지점 대체 지점), - // 최소 1개 이상이어야 완전합니다. - { - "location": [ // 그리드 좌표, 맵 위키에서 얻을 수 있음 - 6, - 4 - ], - "direction_Doc1": "선호 방향, 반드시 해당 방향이라는 의미는 아님 (알고리즘이 자체적으로 판단함)", - "direction_Doc2": "기본값은 없음, 즉 추천 방향이 없으며, 완전히 알고리즘에 의해 결정됨", - "direction_Doc3": "none / left / right / up / down / 无 / 上 / 下 / 左 / 右", - "direction": "left" // (이것은 그리드 6,4에서 왼쪽으로 오퍼레이터를 우선 배치함을 나타냅니다.) - } - ], - ... - ``` + ```json + { + "stage_name": "蓄水池", // 레벨 이름 (중국어) + "replacement_home": [ // 진입 지점 (목표 지점 대체 지점), + // 최소 1개 이상이어야 완전합니다. + { + "location": [ // 그리드 좌표, 맵 위키에서 얻을 수 있음 + 6, + 4 + ], + "direction_Doc1": "선호 방향, 반드시 해당 방향이라는 의미는 아님 (알고리즘이 자체적으로 판단함)", + "direction_Doc2": "기본값은 없음, 즉 추천 방향이 없으며, 완전히 알고리즘에 의해 결정됨", + "direction_Doc3": "none / left / right / up / down / 无 / 上 / 下 / 左 / 右", + "direction": "left" // (이것은 그리드 6,4에서 왼쪽으로 오퍼레이터를 우선 배치함을 나타냅니다.) + } + ], + ... + ``` 2. 배치 그리드 블랙리스트 - 방어를 우선해야 할 지점과 오퍼레이터를 배치하지 않아야 할 지점이 있습니다. 예를 들어 화염구가 지나가는 곳, 보스의 발 밑, 배치하기 좋지 않은 위치 등입니다. + 방어를 우선해야 할 지점과 오퍼레이터를 배치하지 않아야 할 지점이 있습니다. 예를 들어 화염구가 지나가는 곳, 보스의 발 밑, 배치하기 좋지 않은 위치 등입니다. - 이 경우 `blacklist_location`을 도입하여 MAA가 오퍼레이터를 배치하지 않도록 그리드를 블랙리스트에 추가합니다. - ::: info - 여기에 추가된 그리드는 나중에 배치 전략에 포함되더라도 배치되지 않습니다. - ::: + 이 경우 `blacklist_location`을 도입하여 MAA가 오퍼레이터를 배치하지 않도록 그리드를 블랙리스트에 추가합니다. + ::: info + 여기에 추가된 그리드는 나중에 배치 전략에 포함되더라도 배치되지 않습니다. + ::: - ```json - ... - "blacklist_location_Doc": "이것은 사용 예시이며, 맵 '蓄水池'가 필요로 하는 것은 아님.", - "blacklist_location": [ // 오퍼레이터 배치 금지 위치 - [ - 0, - 0 - ], - [ - 1, - 1 - ] - ], - ``` + ```json + ... + "blacklist_location_Doc": "이것은 사용 예시이며, 맵 '蓄水池'가 필요로 하는 것은 아님.", + "blacklist_location": [ // 오퍼레이터 배치 금지 위치 + [ + 0, + 0 + ], + [ + 1, + 1 + ] + ], + ``` 3. 대체 맵 전략 - 예를 들어, 미즈키 로그라이크에서 목표 지점에 몬스터가 있다면 주사위를 사용하여 몬스터 쌓이는 상황을 완화할 수 있습니다. + 예를 들어, 미즈키 로그라이크에서 목표 지점에 몬스터가 있다면 주사위를 사용하여 몬스터 쌓이는 상황을 완화할 수 있습니다. - ```json - "not_use_dice_Doc": "목표 지점 오퍼레이터가 후퇴할 때 MAA가 주사위를 사용할 필요가 있는지 여부. 비어 있으면 기본값은 false입니다.", - "not_use_dice": false, - ``` + ```json + "not_use_dice_Doc": "목표 지점 오퍼레이터가 후퇴할 때 MAA가 주사위를 사용할 필요가 있는지 여부. 비어 있으면 기본값은 false입니다.", + "not_use_dice": false, + ``` ### 이제 긴급 작전인가요? 이제 진정한 실력을 발휘할 때에요! - 맞춤형 전투 전략 @@ -329,120 +328,120 @@ icon: ri:game-fill 1. 그룹을 사용하여 오퍼레이터 배치 - ```json - "deploy_plan": [ // 배치 로직: 위에서 아래로, 왼쪽에서 오른쪽으로 순서대로 - // 첫 번째 오퍼레이터를 찾고, 찾지 못하면 건너뜁니다. - { - - "groups": ["GavialAlter", "Mudrock", "GroundC", "Horn", "Vanguard"], // 이 그룹에서 오퍼레이터를 찾습니다. - "location": [ 6, 4 ], // 첫 번째 오퍼레이터을 그리드 6,4에 배치하고 왼쪽을 향합니다. - "direction": "left", // 찾지 못하면 다음 배치 작업으로 넘어갑니다. - }, - { - "groups": [ "Summoner" ], - "location": [ 6, 3 ], - "direction": "left" - }, - { - "groups": [ "单奶", "群奶" ], - "location": [ 6, 2 ], - "direction": "down" - } - ] - ``` + ```json + "deploy_plan": [ // 배치 로직: 위에서 아래로, 왼쪽에서 오른쪽으로 순서대로 + // 첫 번째 오퍼레이터를 찾고, 찾지 못하면 건너뜁니다. + { - ::: info - MAA는 모든 배치 명령을 평탄화한 후 가장 높은 우선순위 배치 작업을 실행합니다. - 예: [ "Gavial", "Cornerstone", "GroundC"]를 [6,4]에 배치하고, [ "Cornerstone", "GroundC"]를 [6,3]에 배치한 후 MAA는 배치 명령을 포매팅하여 [ "Gavial", "Cornerstone", "GroundC", "Cornerstone", "GroundC"]로 만듭니다. - 전투 중 [6,4]에 있는 "Gavial" 오퍼레이터가 후퇴하면, "Cornerstone" 오퍼레이터가 있다면 [6,4]에 배치되며 [6,3]에는 배치되지 않습니다. - ::: + "groups": ["GavialAlter", "Mudrock", "GroundC", "Horn", "Vanguard"], // 이 그룹에서 오퍼레이터를 찾습니다. + "location": [ 6, 4 ], // 첫 번째 오퍼레이터을 그리드 6,4에 배치하고 왼쪽을 향합니다. + "direction": "left", // 찾지 못하면 다음 배치 작업으로 넘어갑니다. + }, + { + "groups": [ "Summoner" ], + "location": [ 6, 3 ], + "direction": "left" + }, + { + "groups": [ "单奶", "群奶" ], + "location": [ 6, 2 ], + "direction": "down" + } + ] + ``` + + ::: info + MAA는 모든 배치 명령을 평탄화한 후 가장 높은 우선순위 배치 작업을 실행합니다. + 예: [ "Gavial", "Cornerstone", "GroundC"]를 [6,4]에 배치하고, [ "Cornerstone", "GroundC"]를 [6,3]에 배치한 후 MAA는 배치 명령을 포매팅하여 [ "Gavial", "Cornerstone", "GroundC", "Cornerstone", "GroundC"]로 만듭니다. + 전투 중 [6,4]에 있는 "Gavial" 오퍼레이터가 후퇴하면, "Cornerstone" 오퍼레이터가 있다면 [6,4]에 배치되며 [6,3]에는 배치되지 않습니다. + ::: 2. 특정 시간에 오퍼레이터 배치 - ::: tip - 특정 단일 절단 오퍼레이터나 포드가 필요한 사용 시나리오에 적합합니다. - ::: + ::: tip + 특정 단일 절단 오퍼레이터나 포드가 필요한 사용 시나리오에 적합합니다. + ::: - ```json - "deploy_plan": [ - { - "groups": [ "StrangeVirtue", "Assassin", "Vanguard", "OtherFloors" ], - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 0, 3 ] // 처치 수가 0 - 3일 때만 이 작업을 수행합니다. - }, - { - "groups": [ "StrangeVirtue", "Assassin", "Vanguard", "OtherFloors" ], - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 6, 10 ] - }, - ... - ] - ``` + ```json + "deploy_plan": [ + { + "groups": [ "StrangeVirtue", "Assassin", "Vanguard", "OtherFloors" ], + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 0, 3 ] // 처치 수가 0 - 3일 때만 이 작업을 수행합니다. + }, + { + "groups": [ "StrangeVirtue", "Assassin", "Vanguard", "OtherFloors" ], + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 6, 10 ] + }, + ... + ] + ``` 3. 특정 시간에 오퍼레이터 퇴각 ::: tip 때때로 포드가 너무 강해 필드를 유지하거나 라인업을 이동하기 위해 배치해야 할 때가 있습니다. 이때 퇴각하세요! ::: - ```json - "retreat_plan": [ // 특정 시간에 오퍼레이터 퇴각 대상 - { - "location": [ 4, 1 ], - "condition": [ 7, 8 ] // 처치 수가 7 - 8일 때 [4,1]에 있는 오퍼레이터를 제거합니다. 없으면 건너뜁니다. - } - ] - ``` + ```json + "retreat_plan": [ // 특정 시간에 오퍼레이터 퇴각 대상 + { + "location": [ 4, 1 ], + "condition": [ 7, 8 ] // 처치 수가 7 - 8일 때 [4,1]에 있는 오퍼레이터를 제거합니다. 없으면 건너뜁니다. + } + ] + ``` -4. 특정 시간에 스킬 비활성화 (*TODO*) +4. 특정 시간에 스킬 비활성화 (_TODO_) 5. 추가 필드 (권장하지 않음) - ```json - "role_order_Doc": "오퍼레이터 유형 배치 순서, 지정되지 않은 부분은 Guard, Vanguard, Medic, Defender, Sniper, Caster, Supporter, Specialist, Summoner 순서로 채워집니다.", - "role_order": [ // 권장하지 않음, deploy_plan 필드를 구성하세요. - "warrior", - "pioneer", - "medic", - "tank", - "sniper", - "caster", - "support", - "special", - "drone" - ], - "force_air_defense_when_deploy_blocking_num_Doc": "필드에 10000개의 블록 유닛이 있을 때 강제적으로 총 1쌍의 공중 유닛을 배치합니다 (기본 배치 로직에는 영향을 미치지 않음), 이 기간 동안 의료 유닛 배치는 금지되지 않습니다 (기본값은 false).", - "force_air_defense_when_deploy_blocking_num": { // 권장하지 않음, deploy_plan 필드를 구성하세요. - "melee_num": 10000, - "air_defense_num": 1, - "ban_medic": false - }, - "force_deploy_direction_Doc": "특정 직업에 대한 강제 배치 방향", - "force_deploy_direction": [ // 권장하지 않음, deploy_plan 필드를 구성하세요. - { - "location": [ - 1, - 1 - ], - "role_Doc": "입력된 직업에 대한 강제 배치 방향 적용", - "role": [ - "warrior", - "pioneer" - ], - "direction": "up" - }, - { - "location": [ - 3, - 1 - ], - "role": [ - "sniper" - ], - "direction": "left" - } - ], - ``` + ```json + "role_order_Doc": "오퍼레이터 유형 배치 순서, 지정되지 않은 부분은 Guard, Vanguard, Medic, Defender, Sniper, Caster, Supporter, Specialist, Summoner 순서로 채워집니다.", + "role_order": [ // 권장하지 않음, deploy_plan 필드를 구성하세요. + "warrior", + "pioneer", + "medic", + "tank", + "sniper", + "caster", + "support", + "special", + "drone" + ], + "force_air_defense_when_deploy_blocking_num_Doc": "필드에 10000개의 블록 유닛이 있을 때 강제적으로 총 1쌍의 공중 유닛을 배치합니다 (기본 배치 로직에는 영향을 미치지 않음), 이 기간 동안 의료 유닛 배치는 금지되지 않습니다 (기본값은 false).", + "force_air_defense_when_deploy_blocking_num": { // 권장하지 않음, deploy_plan 필드를 구성하세요. + "melee_num": 10000, + "air_defense_num": 1, + "ban_medic": false + }, + "force_deploy_direction_Doc": "특정 직업에 대한 강제 배치 방향", + "force_deploy_direction": [ // 권장하지 않음, deploy_plan 필드를 구성하세요. + { + "location": [ + 1, + 1 + ], + "role_Doc": "입력된 직업에 대한 강제 배치 방향 적용", + "role": [ + "warrior", + "pioneer" + ], + "direction": "up" + }, + { + "location": [ + 3, + 1 + ], + "role": [ + "sniper" + ], + "direction": "left" + } + ], + ``` ### 오퍼레이터의 플레이 스타일에 대한 특별한 이해가 있습니까? -- 특정 오퍼레이터의 정교한 운영 @@ -508,7 +507,7 @@ OCR이 조우를 인식하지만 선택은 고정된 위치에서 이루어집 ... ``` -### 팀 상황에 따라 특정 옵션의 우선순위 동적으로 설정 (*TODO*) +### 팀 상황에 따라 특정 옵션의 우선순위 동적으로 설정 (_TODO_) ## 통합 전략 단계 4: 무역 상점 수집 우선순위 @@ -531,7 +530,7 @@ OCR이 조우를 인식하지만 선택은 고정된 위치에서 이루어집 "effect": "每有5源石锭, 所有我方单位的攻击速度+7", // 수집품 효과 (운영에는 영향을 미치지 않으며 정렬에 유용함) "no": 167 // 수집품 번호 (위키에서 찾을 수 있으며, 운영에는 영향을 미치지 않음) }, - + ... { "name": "Hand of Diffusion", @@ -540,7 +539,7 @@ OCR이 조우를 인식하지만 선택은 고정된 위치에서 이루어집 // Hand of Diffusion을 만났을 때 구매하려고 시도함) ], "effect": "[Diffusion Artist], [Chain Artist], and [Blast Artist] regain 2 SP for each unit they deal damage to.", - "no": 136 + "no": 136 }, ... @@ -551,7 +550,7 @@ OCR이 조우를 인식하지만 선택은 고정된 위치에서 이루어집 // Halberd-Breaker를 만났을 때 구매하려고 시도함) ], "effect": "All [Guard] Operators members have -40% Defence, but +40% Attack Power and +30% Attack Speed.", - "no": 16 + "no": 16 }, ... @@ -563,7 +562,7 @@ OCR이 조우를 인식하지만 선택은 고정된 위치에서 이루어집 }, ``` -## 원하는 로직 (*TODO*) +## 원하는 로직 (_TODO_) ### 자동 포메이션 로직 diff --git a/docs/ko-kr/protocol/integration.md b/docs/ko-kr/protocol/integration.md index 8b9a97db3f..2b98e63a65 100644 --- a/docs/ko-kr/protocol/integration.md +++ b/docs/ko-kr/protocol/integration.md @@ -335,7 +335,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p "tools_to_craft": [ string, // 자동으로 제작되는 아이템, 선택 사항, 기본값은 형광봉 ... - ] + ] // 부분 문자열을 채우는 것이 좋습니다 "increment_mode": int, // 클릭 유형, 선택 사항. 기본값은 0 // 0 - 연속 클릭 @@ -344,7 +344,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p } ``` -- `Custom` +- `Custom` 사용자 정의 태스크 @@ -359,7 +359,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p } ``` -- `SingleStep` +- `SingleStep` 단일 단계 태스크 (현재로서는 Copilot만 지원) @@ -378,7 +378,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p } ``` -- `VideoRecognition` +- `VideoRecognition` 비디오 인식, 현재로서는 전투 비디오만 지원합니다. diff --git a/docs/ko-kr/protocol/remote-control-schema.md b/docs/ko-kr/protocol/remote-control-schema.md index f3977450ed..87959d74cb 100644 --- a/docs/ko-kr/protocol/remote-control-schema.md +++ b/docs/ko-kr/protocol/remote-control-schema.md @@ -88,7 +88,8 @@ MAA는 이 엔드 포인트를 계속하여 폴링하여 실행해야하는 작 - Settings-[SettingsName] 작업 유형의 유형 매개 변수의 선택 가능한 값은 Settings-ConnectionAddress, Settings-Stage1입니다. - 설정 시리즈 작업은 여전히 순서대로 실행되며 작업을 받은 즉시 실행되지 않으며 이전 작업 뒤에 배치됩니다. - 여러 즉시 실행 작업은 순서대로 실행되지만 이러한 작업은 모두 빠르게 실행되므로 순서에 관심을 두지 않아도됩니다. - ::: + +::: ## 작업 보고 엔드 포인트 @@ -158,4 +159,4 @@ MAA의 설정에 올바르게 MAA 연결을 만들려면 웹 사이트에서 사 작업이 완료되면 MAA가 reportStatus를 호출하여 결과를 보고하면 웹 사이트는 결과를받고 사용자에게 페이지를 업데이트하여 작업 결과를 표시합니다. - \ No newline at end of file + diff --git a/docs/ko-kr/protocol/sss-schema.md b/docs/ko-kr/protocol/sss-schema.md index 25e81db8d5..7763c6ed0c 100644 --- a/docs/ko-kr/protocol/sss-schema.md +++ b/docs/ko-kr/protocol/sss-schema.md @@ -3,7 +3,6 @@ order: 7 icon: game-icons:prisoner --- - # 보안파견 스키마 ::: tip diff --git a/docs/ko-kr/protocol/task-schema.md b/docs/ko-kr/protocol/task-schema.md index dfe2a2b5b8..eb907a4f5c 100644 --- a/docs/ko-kr/protocol/task-schema.md +++ b/docs/ko-kr/protocol/task-schema.md @@ -73,7 +73,7 @@ It is recommended to use [Visual Studio Code](https://code.visualstudio.com/) an "cache": false, // 선택 사항, 작업이 캐싱을 사용하는지 여부를 나타냅니다. 기본값은 false입니다. // 최초 인식 이후에는 해당 위치만 인식하며, 성능을 크게 개선할 수 있습니다. - + // 단, 대상 인식 위치가 절대로 변하지 않을 작업에만 사용하세요. 대상 인식 위치가 항상 변하는 경우 false로 설정하세요. @@ -215,13 +215,11 @@ It is recommended to use [Visual Studio Code](https://code.visualstudio.com/) an ``` - 작업 "B@A"가 `tasks.json`에 정의되어 있다면 - 1. `B@A`의 `algorithm` 필드가 `A`의 `algorithm`과 다른 경우, 파생된 클래스 매개변수는 상속되지 않습니다(단지 `TaskInfo`로 정의된 매개변수만 상속됨). 2. 이미지 매칭 작업의 경우, 명시적으로 정의되지 않으면 `template`은 `B@A.png`가 됩니다(단지 "A" 작업의 `template` 이름을 상속하지 않음). 그렇지 않은 경우 다른 파생된 클래스 매개변수는 "A" 작업에서 직접 상속됩니다. 3. `TaskInfo` 기본 클래스에 정의된 매개변수 (모든 유형의 작업에 해당하는 매개변수, 예를 들어 algorithm, roi, next 등)가 `B@A` 내에서 명시적으로 정의되지 않은 경우, 앞에서 언급한 `sub` 등 다섯 개의 필드를 제외한 나머지 매개변수는 `B@` 접두어가 추가된 상속시 추가됩니다. 그 외의 매개변수는 `A` 작업의 매개변수를 직접 상속합니다. > _참고: `"XXX#self"`는 `"#self"`와 동일한 의미를 갖습니다._ - > ### 기반 작업 diff --git a/docs/ko-kr/readme.md b/docs/ko-kr/readme.md index 6aaa59767f..467f438428 100644 --- a/docs/ko-kr/readme.md +++ b/docs/ko-kr/readme.md @@ -26,7 +26,7 @@ MAA는 MAA Assistant Arknights의 약자입니다 이미지 인식을 기반으로, 한 번의 클릭만으로 그날의 모든 작업을 끝내드립니다! -개발 진행 중입니다 ✿✿ヽ(°▽°)ノ✿ +개발 진행 중입니다 ✿✿ヽ(°▽°)ノ✿ ::: @@ -196,7 +196,7 @@ MAA의 개선을 위한 개발/테스트에 기여해준 모든 친구들에게 Discord 서버: [Discord 링크](https://discord.gg/23DfZ9uA4V) 사용자 그룹: [Telegram](https://t.me/+Mgc2Zngr-hs3ZjU1) [전략 JSON 공유](https://prts.plus) -Bilibili 라이브 방송: [MrEO 방송](https://live.bilibili.com/2808861) 코딩 방송 & [MAA-Official 방송](https://live.bilibili.com/27548877) 게임/잡담 +Bilibili 라이브 방송: [MrEO 방송](https://live.bilibili.com/2808861) 코딩 방송 & [MAA-Official 방송](https://live.bilibili.com/27548877) 게임/잡담 [명일방주 무관 기술 공유 & 만담 (QQ 그룹)](https://jq.qq.com/?_wv=1027&k=ypbzXcA2): 지옥 같아요! [개발자 그룹 (QQ 그룹)](https://jq.qq.com/?_wv=1027&k=JM9oCk3C) diff --git a/docs/package.json b/docs/package.json index d9f208dc9d..7c4134ddf6 100644 --- a/docs/package.json +++ b/docs/package.json @@ -7,6 +7,7 @@ "author": "bakashigure ", "license": "AGPL-3.0", "private": true, + "packageManager": "pnpm@10.17.1", "devDependencies": { "@iconify/vue": "^5.0.0", "@vuepress/bundler-vite": "2.0.0-rc.24", diff --git a/docs/zh-cn/develop/ci-tutorial.md b/docs/zh-cn/develop/ci-tutorial.md index fc6a6fb2a4..62302f6266 100644 --- a/docs/zh-cn/develop/ci-tutorial.md +++ b/docs/zh-cn/develop/ci-tutorial.md @@ -15,15 +15,15 @@ MAA 借助 Github Action 完成了大量的自动化工作,包括网站的构 工作流的文件均存放在 `.github/workflows` 下,各个文件可以按功能分为以下几部分: -+ [代码测试](#代码测试) -+ [代码构建](#代码构建) -+ [版本发布](#版本发布) -+ [资源更新](#资源更新) -+ [网站构建](#网站构建) -+ [Issues 管理](#issues-管理) -+ [Pull Requests 管理](#pull-requests-管理) -+ [MirrorChyan 相关](#mirrorchyan-相关) -+ [其他](#其他) +- [代码测试](#代码测试) +- [代码构建](#代码构建) +- [版本发布](#版本发布) +- [资源更新](#资源更新) +- [网站构建](#网站构建) +- [Issues 管理](#issues-管理) +- [Pull Requests 管理](#pull-requests-管理) +- [MirrorChyan 相关](#mirrorchyan-相关) +- [其他](#其他) 此外,我们还通过 [pre-commit.ci](https://pre-commit.ci/) 实现了代码的自动格式化和图片资源的自动优化,它在发起 PR 后会自动执行,一般无需特别在意。 @@ -51,10 +51,10 @@ MAA 借助 Github Action 完成了大量的自动化工作,包括网站的构 版本发布,简称发版,是向用户发布更新的必要操作,由以下工作流组成 -+ `release-nightly-ota.yml` 发布内测版 -+ `release-ota.yml` 发布正式版/公测版 - + `gen-changelog.yml` 为正式版/公测版生成 changelog - + `pr-auto-tag.yml` 对正式版/公测版生成 tag +- `release-nightly-ota.yml` 发布内测版 +- `release-ota.yml` 发布正式版/公测版 + - `gen-changelog.yml` 为正式版/公测版生成 changelog + - `pr-auto-tag.yml` 对正式版/公测版生成 tag ::: tip 上述文件名内的 ota 意为 Over-the-Air,也就是我们常说的“增量更新包”,因此 MAA 的发版过程实际上包含了对过往版本构建 OTA 包的步骤 @@ -82,9 +82,9 @@ MAA 借助 Github Action 完成了大量的自动化工作,包括网站的构 这部分工作流主要负责 MAA 的资源更新以及优化,具体工作流如下: -+ `res-update-game.yml` 定期执行,从指定的仓库拉取游戏资源 -+ `sync-resource.yml` 将资源同步到 MaaResource 仓库,用于资源更新 -+ `optimize-templates.yml` 优化模板图大小 +- `res-update-game.yml` 定期执行,从指定的仓库拉取游戏资源 +- `sync-resource.yml` 将资源同步到 MaaResource 仓库,用于资源更新 +- `optimize-templates.yml` 优化模板图大小 ### 网站构建 @@ -119,8 +119,8 @@ MAA 借助 Github Action 完成了大量的自动化工作,包括网站的构 MirrorChyan 是有偿的更新镜像服务,与其相关的工作流如下: -+ `mirrorchyan.yml` 同步更新包到 MirrorChyan -+ `mirrorchyan_release_note.yml` 生成 MirrorChyan 的 Release Note +- `mirrorchyan.yml` 同步更新包到 MirrorChyan +- `mirrorchyan_release_note.yml` 生成 MirrorChyan 的 Release Note ### 其他 diff --git a/docs/zh-cn/develop/development.md b/docs/zh-cn/develop/development.md index ac51c49a80..4de309ae8a 100644 --- a/docs/zh-cn/develop/development.md +++ b/docs/zh-cn/develop/development.md @@ -21,44 +21,42 @@ icon: iconoir:developer 2. 打开 [MAA 主仓库](https://github.com/MaaAssistantArknights/MaaAssistantArknights),点击 `Fork`,继续点击 `Create fork` 3. 克隆你自己仓库下的 dev 分支到本地,并拉取子模块 - ```bash - git clone --recurse-submodules <你的仓库的 git 链接> -b dev - ``` + ```bash + git clone --recurse-submodules <你的仓库的 git 链接> -b dev + ``` - ::: warning - 如果正在使用 Visual Studio 等不附带 `--recurse-submodules` 参数的 Git GUI,则需在克隆后再执行 `git submodule update --init` 以拉取子模块。 - ::: + ::: warning + 如果正在使用 Visual Studio 等不附带 `--recurse-submodules` 参数的 Git GUI,则需在克隆后再执行 `git submodule update --init` 以拉取子模块。 + ::: 4. 下载预构建的第三方库 - **需要有 Python 环境,请自行搜索 Python 安装教程** + **需要有 Python 环境,请自行搜索 Python 安装教程** - ```cmd - python tools/maadeps-download.py - ``` + ```cmd + python tools/maadeps-download.py + ``` 5. 配置编程环境 - - - 下载并安装 `CMake` - - 下载并安装 `Visual Studio 2022 community`, 安装的时候需要选中 `基于 C++ 的桌面开发` 和 `.NET 桌面开发`。 + - 下载并安装 `CMake` + - 下载并安装 `Visual Studio 2022 community`, 安装的时候需要选中 `基于 C++ 的桌面开发` 和 `.NET 桌面开发`。 6. 执行 cmake 项目配置 - ```cmd - mkdir -p build - cmake -G "Visual Studio 17 2022" -B build -DBUILD_WPF_GUI=ON -DBUILD_DEBUG_DEMO=ON - ``` + ```cmd + mkdir -p build + cmake -G "Visual Studio 17 2022" -B build -DBUILD_WPF_GUI=ON -DBUILD_DEBUG_DEMO=ON + ``` 7. 双击打开 `build/MAA.sln` 文件,Visual Studio 会自动加载整个项目。 8. 设置 VS - - - VS 上方配置选择 `Debug` `x64` - - 右键 `MaaWpfGui` - 设为启动项目 - - 按 F5 运行 + - VS 上方配置选择 `Debug` `x64` + - 右键 `MaaWpfGui` - 设为启动项目 + - 按 F5 运行 9. 到这里,你就可以愉快地 ~~瞎 JB 改~~ 发电了 10. 开发过程中,每一定数量,记得提交一个 Commit, 别忘了写上 Message - 假如你不熟悉 git 的使用,你可能想要新建一个分支进行更改,而不是直接提交在 `dev` 上 + 假如你不熟悉 git 的使用,你可能想要新建一个分支进行更改,而不是直接提交在 `dev` 上 ```bash git branch your_own_branch @@ -75,30 +73,29 @@ icon: iconoir:developer 12. 打开 [MAA 主仓库](https://github.com/MaaAssistantArknights/MaaAssistantArknights)。提交一个 Pull Request,等待管理员通过。别忘了你是在 dev 分支上修改,别提交到 master 分支去了 13. 当 MAA 原仓库出现更改(别人做的),你可能需要把这些更改同步到你的分支 - 1. 关联 MAA 原仓库 - ```bash - git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git - ``` + ```bash + git remote add upstream https://github.com/MaaAssistantArknights/MaaAssistantArknights.git + ``` 2. 从 MAA 原仓库拉取更新 - ```bash - git fetch upstream - ``` + ```bash + git fetch upstream + ``` 3. 变基(推荐)或者合并修改 - ```bash - git rebase upstream/dev # 变基 - ``` + ```bash + git rebase upstream/dev # 变基 + ``` - 或者 + 或者 - ```bash - git merge # 合并 - ``` + ```bash + git merge # 合并 + ``` 4. 重复上述 7, 8, 9, 10 中的操作 @@ -114,11 +111,11 @@ MAA 使用一系列的格式化工具来保证仓库中的代码和资源文件 目前启用的格式化工具如下: -| 文件类型 | 格式化工具 | -| --- | --- | -| C++ | [clang-format](https://clang.llvm.org/docs/ClangFormat.html) | -| Json/Yaml | [Prettier](https://prettier.io/) | -| Markdown | [markdownlint](https://github.com/DavidAnson/markdownlint-cli2) | +| 文件类型 | 格式化工具 | +| --------- | --------------------------------------------------------------- | +| C++ | [clang-format](https://clang.llvm.org/docs/ClangFormat.html) | +| Json/Yaml | [Prettier](https://prettier.io/) | +| Markdown | [markdownlint](https://github.com/DavidAnson/markdownlint-cli2) | ### 利用 Pre-commit Hooks 自动进行代码格式化 @@ -126,10 +123,10 @@ MAA 使用一系列的格式化工具来保证仓库中的代码和资源文件 2. 在项目根目录下执行以下命令 - ```bash - pip install pre-commit - pre-commit install - ``` + ```bash + pip install pre-commit + pre-commit install + ``` 如果pip安装后依然无法运行 Pre-commit,请确认 PIP 安装地址已被添加到 PATH @@ -139,9 +136,9 @@ MAA 使用一系列的格式化工具来保证仓库中的代码和资源文件 1. 安装 clang-format 20.1.0 或更高版本 - ```bash - python -m pip install clang-format - ``` + ```bash + python -m pip install clang-format + ``` 2. 使用 Everything 等工具 找到 clang-format.exe 的安装位置。作为参考,若您使用了 Anaconda,clang-format.exe 将安装在 YourAnacondaPath/Scripts/clang-format.exe @@ -160,6 +157,4 @@ MAA 使用一系列的格式化工具来保证仓库中的代码和资源文件 创建 GitHub Codespace 自动配置 C++ 开发环境 -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights) - -随后根据 VSCode 的提示或 [Linux 教程](./linux-tutorial.md) 配置 GCC 12 和 CMake 工程 +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg?color=green)](https://codespaces.new/MaaAssistantArknights/MaaAssistantArknights?devcontainer_path=.devcontainer%2F1%2Fdevcontainer.json) diff --git a/docs/zh-cn/develop/documentation-guidelines.md b/docs/zh-cn/develop/documentation-guidelines.md index 676d072be9..ac19f10a92 100644 --- a/docs/zh-cn/develop/documentation-guidelines.md +++ b/docs/zh-cn/develop/documentation-guidelines.md @@ -84,7 +84,7 @@ icon: jam:write-f **输入:** -```md +```markdown MaaAssistantArknight 是由 ==很多猪== 开发的 ``` @@ -183,6 +183,7 @@ MaaAssistantArknight 是由 ==很多猪== 开发的 ::: 4. 结束 + :::: ## 智能图片容器 diff --git a/docs/zh-cn/develop/issue-bot-usage.md b/docs/zh-cn/develop/issue-bot-usage.md index 8227f46d3f..060940d9d9 100644 --- a/docs/zh-cn/develop/issue-bot-usage.md +++ b/docs/zh-cn/develop/issue-bot-usage.md @@ -47,7 +47,7 @@ Issue Bot 会对拉取请求标题的格式进行简单审查。它会增加 `am - `Skip {LABEL_NAME}` 可以保证不增加标签。 - `Skip labels` 可以保证不增加任何标签。 -- 以下几种方法可以为议题增加 `fixed` 标签:1 +- 以下几种方法可以为议题增加 `fixed` 标签:1 - `https://github.com/MaaAssistantArknights/MaaAssistantArknights/commit/{COMMIT_HASH} fixed` - `fixed by https://github.com/MaaAssistantArknights/MaaAssistantArknights/commit/{COMMIT_HASH}` - `{VERSION} fixed` diff --git a/docs/zh-cn/develop/linux-tutorial.md b/docs/zh-cn/develop/linux-tutorial.md index cf1177aa21..09a4bee18a 100644 --- a/docs/zh-cn/develop/linux-tutorial.md +++ b/docs/zh-cn/develop/linux-tutorial.md @@ -18,63 +18,60 @@ Mac 可以使用 `tools/build_macos_universal.zsh` 脚本进行编译。建议 ## 编译过程 1. 下载编译所需的依赖 + - Ubuntu/Debian - - Ubuntu/Debian + ```bash + sudo apt install cmake + ``` - ```bash - sudo apt install cmake - ``` + - Arch Linux - - Arch Linux - - ```bash - sudo pacman -S --needed cmake - ``` + ```bash + sudo pacman -S --needed cmake + ``` 2. 构建第三方库 - 可以选择下载预构建的依赖库或从头进行编译 + 可以选择下载预构建的依赖库或从头进行编译 + - 下载预构建的第三方库 (推荐的) - - 下载预构建的第三方库 (推荐的) + > **Note** + > ~~包含在相对较新的 Linux 发行版 (Ubuntu 22.04) 中编译的动态库, 如果您系统中的 libstdc++ 版本较老, 可能遇到 ABI 不兼容的问题~~. + > 目前已经基于交叉编译降低了运行环境, 仅需要依赖 glibc 2.31 (ubuntu 20.04). - > **Note** - > ~~包含在相对较新的 Linux 发行版 (Ubuntu 22.04) 中编译的动态库, 如果您系统中的 libstdc++ 版本较老, 可能遇到 ABI 不兼容的问题~~. - > 目前已经基于交叉编译降低了运行环境, 仅需要依赖 glibc 2.31 (ubuntu 20.04). + ```bash + python tools/maadeps-download.py + ``` - ```bash - python tools/maadeps-download.py - ``` + 如果您发现上面的方法下载的库由于 ABI 版本等原因无法在您的系统上运行且不希望使用容器等方案, 也可以尝试从头编译 + - 自行构建第三方库 (将花费较长时间) - 如果您发现上面的方法下载的库由于 ABI 版本等原因无法在您的系统上运行且不希望使用容器等方案, 也可以尝试从头编译 - - - 自行构建第三方库 (将花费较长时间) - - ```bash - git clone https://github.com/MaaAssistantArknights/MaaDeps - cd MaaDeps - # 如果系统环境过低无法使用我们预构建的 llvm 20, 请考虑不使用交叉编译, 直接使用本地编译环境. - # 需要调整 MaaDeps/cmake 中的 toolchain 配置. - python linux-toolchain-download.py - python build.py - ``` + ```bash + git clone https://github.com/MaaAssistantArknights/MaaDeps + cd MaaDeps + # 如果系统环境过低无法使用我们预构建的 llvm 20, 请考虑不使用交叉编译, 直接使用本地编译环境. + # 需要调整 MaaDeps/cmake 中的 toolchain 配置. + python linux-toolchain-download.py + python build.py + ``` 3. 编译 MAA - ```bash - cmake -B build \ - -DINSTALL_RESOURCE=ON \ - -DINSTALL_PYTHON=ON \ - -DCMAKE_TOOLCHAIN_FILE=MaaDeps/cmake/maa-x64-linux-toolchain.cmake - cmake --build build - ``` + ```bash + cmake -B build \ + -DINSTALL_RESOURCE=ON \ + -DINSTALL_PYTHON=ON \ + -DCMAKE_TOOLCHAIN_FILE=MaaDeps/cmake/maa-x64-linux-toolchain.cmake + cmake --build build + ``` - 来将 MAA 安装到目标位置, 注意 MAA 推荐通过指定 `LD_LIBRARY_PATH` 来运行, 不要使用管理员权限将 MAA 装入 `/usr` + 来将 MAA 安装到目标位置, 注意 MAA 推荐通过指定 `LD_LIBRARY_PATH` 来运行, 不要使用管理员权限将 MAA 装入 `/usr` - > 现在应该不需要指定 `LD_LIBRARY_PATH` 即可运行 + > 现在应该不需要指定 `LD_LIBRARY_PATH` 即可运行 - ```bash - cmake --install build --prefix - ``` + ```bash + cmake --install build --prefix + ``` ## 集成文档 diff --git a/docs/zh-cn/develop/pr-tutorial.md b/docs/zh-cn/develop/pr-tutorial.md index 151b9edf45..9ccea12f36 100644 --- a/docs/zh-cn/develop/pr-tutorial.md +++ b/docs/zh-cn/develop/pr-tutorial.md @@ -72,79 +72,79 @@ icon: mingcute:git-pull-request-fill 1. 首先进入 MAA 主仓库,点右上角这个按钮 Fork 一份代码 - + 2. 然后直接点击 Create Fork - + 3. 接下来来到了你的个人仓库,可以看到标题是 "你的名字/MaaAssistantArknights",下面一行小字 forked from MaaAssistantArknights/MaaAssistantArknights (复制自 MAA 主仓库) - + 4. 找到你要改的文件,可以点 "Go to file" 进行全局搜索,也可以直接在下面的文件夹里翻(如果你知道文件在哪的话) - + 5. 打开文件后,直接点击文件右上角的 ✏️ 进行编辑 - + 6. 开改!(如果是资源文件这种,我们建议先在你电脑上的 MAA 文件夹里测试修改,确认没问题了再粘贴到网页上,避免改错了) 7. 改完了,点击右上角的 👇 这个按钮,打开提交页面,写一下你改了啥 - + - 我们有一个简单的提交标题[命名格式](https://www.conventionalcommits.org/zh-hans/v1.0.0/),最好可以遵守一下,当然如果实在看不懂也可以先随便写 + 我们有一个简单的提交标题[命名格式](https://www.conventionalcommits.org/zh-hans/v1.0.0/),最好可以遵守一下,当然如果实在看不懂也可以先随便写 - + 8. 还有第二个文件要改的?改完了发现弄错了想再改改?都没关系!重复步骤 4-7 即可! 9. 全改好了进行 PR !直接点 Code 回到**个人仓库**的主页 - 如果有 Compare & Pull Request 按钮,那最好,直接点他! - 如果没有也不用着急,点下面的 Contribute(贡献)按钮,再点 Open Pull Request 也是一样的 + 如果有 Compare & Pull Request 按钮,那最好,直接点他! + 如果没有也不用着急,点下面的 Contribute(贡献)按钮,再点 Open Pull Request 也是一样的 - + 10. 这时候来到了主仓库的 PR 页面,请核对一下你要 PR 的是不是你想提交的 如图中,中间有个向左的箭头,是将右边的的 个人姓名/MAA 的 dev 分支,申请合并到 主仓库/MAA 的 dev 分支 diff --git a/docs/zh-cn/develop/vsc-ext-tutorial.md b/docs/zh-cn/develop/vsc-ext-tutorial.md index 2220522bf0..e5dca86a4c 100644 --- a/docs/zh-cn/develop/vsc-ext-tutorial.md +++ b/docs/zh-cn/develop/vsc-ext-tutorial.md @@ -5,8 +5,8 @@ icon: iconoir:code-brackets # 专用 VSCode 插件教程 -* [插件商店](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) -* [仓库](https://github.com/neko-para/maa-support-extension) +- [插件商店](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) +- [仓库](https://github.com/neko-para/maa-support-extension) ## 安装 @@ -60,10 +60,10 @@ icon: iconoir:code-brackets 插件支持定时扫描并分析所有任务. -* 检查是否有重名任务定义 -* 检查是否有未知任务引用 -* 检查是否有未知图片引用 -* 检查单个任务中是否有重复的任务引用 +- 检查是否有重名任务定义 +- 检查是否有未知任务引用 +- 检查是否有未知图片引用 +- 检查单个任务中是否有重复的任务引用 #### 多路径资源支持 @@ -83,11 +83,11 @@ icon: iconoir:code-brackets > 使用 `Ctrl+Shift+P` (MacOS 上则是 `Command+Shift+P`) 呼出命令面板 -* 选择并连接控制器后, 可使用 `截图` 按钮直接获取截图 -* 可使用 `上传` 按钮手动上传 -* 按住 `Ctrl` 键, 框选需要裁剪的区域 -* 使用滚轮可进行缩放 -* 裁剪完成后, 使用 `下载` 按钮, 可自动将裁剪结果保存到激活资源的最顶层的图片目录 +- 选择并连接控制器后, 可使用 `截图` 按钮直接获取截图 +- 可使用 `上传` 按钮手动上传 +- 按住 `Ctrl` 键, 框选需要裁剪的区域 +- 使用滚轮可进行缩放 +- 裁剪完成后, 使用 `下载` 按钮, 可自动将裁剪结果保存到激活资源的最顶层的图片目录 ### 底部状态栏 diff --git a/docs/zh-cn/manual/connection.md b/docs/zh-cn/manual/connection.md index 26b210465e..770b23491d 100644 --- a/docs/zh-cn/manual/connection.md +++ b/docs/zh-cn/manual/connection.md @@ -63,7 +63,6 @@ MAA 可以通过当前**正在运行的单个模拟器**自动检测并填充 AD ::: details 备选方案 - 方案 1 : 使用 ADB 命令查看模拟器端口 - 1. 启动**一个**模拟器,并确保没有其他安卓设备连接在此计算机上。 2. 在存放有 ADB 可执行文件的文件夹中启动终端。 3. 执行以下命令。 @@ -86,7 +85,6 @@ MAA 可以通过当前**正在运行的单个模拟器**自动检测并填充 AD 使用 `127.0.0.1:<端口>` 或 `emulator-<四位数字>` 作为连接地址。 - 方案 2 : 查找已建立的 ADB 连接 - 1. 执行方案 1。 2. 按 `徽标键+S` 打开搜索栏,输入 `资源监视器` 并打开。 3. 切换到 `网络` 选项卡,在 `侦听端口` 的名称列中查找模拟器进程名,如 `HD-Player.exe`。 @@ -131,10 +129,9 @@ MAA 现在会尝试从注册表中读取 `bluestacks.conf` 的存储位置,当 ::: 1. 在蓝叠模拟器的数据目录下找到 `bluestacks.conf` 这个文件 - - 国际版默认路径为 `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` - 中国内地版默认路径为 `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` - + 注:`C:\ProgramData`为隐藏目录,必要时请在文件资源管理器的地址栏中直接粘贴该地址,以便进入目录并进行寻找。 2. 如果是第一次使用,请运行一次 MAA,使 MAA 自动生成配置文件。 diff --git a/docs/zh-cn/manual/device/android.md b/docs/zh-cn/manual/device/android.md index 59d2bdce51..7dc080b256 100644 --- a/docs/zh-cn/manual/device/android.md +++ b/docs/zh-cn/manual/device/android.md @@ -17,6 +17,7 @@ icon: mingcute:android-fill 3. 由于 MAA 仅支持 `16:9` 比例的分辨率,所以非 `16:9` 或 `9:16` 屏幕比例的设备需要强制修改分辨率,这包含大多数现代设备。若被连接设备屏幕分辨率比例原生为 `16:9` 或 `9:16`,则可跳过 `更改分辨率` 部分。 4. 请将设备导航方式切换为除 `全面屏手势` 以外的方式,如 `经典导航键` 等以避免误操作。 5. 请将游戏内设置中的 `异形屏UI适配` 一项调整为 0 以避免任务出错。 + ::: ::: tip @@ -36,7 +37,6 @@ icon: mingcute:android-fill ``` - 成功执行后会给出已连接 `USB 调试` 设备的信息。 - - 连接成功的例子: ```bash @@ -118,7 +118,6 @@ icon: mingcute:android-fill ``` 2. 将第一个文件重命名为 `startup.bat`,第二个文件重命名为 `finish.bat`。 - - 如果重命名后没有弹出修改扩展名的二次确认对话框,且文件图标没有变化,请自行搜索“Windows 如何显示文件扩展名”。 3. 在 MAA 的 `设置` - `连接设置` - `开始前脚本` 和 `结束后脚本` 中分别填入 `startup.bat` 和 `finish.bat`。 @@ -149,7 +148,6 @@ icon: mingcute:android-fill ``` 2. 查看设备 IP 地址。 - - 进入手机 `设置` - `WLAN`,点击当前已连接的无线网络查看 IP 地址。 - 各类品牌设备设置位置不同,请自行查找。 @@ -165,7 +163,6 @@ icon: mingcute:android-fill 1. 进入手机开发者选项,点击 `无线调试` 并开启,点击确定,点击 `使用配对码配对设备`,在配对完成前不要关闭出现的弹窗。 2. 进行配对。 - 1. 在命令提示符中输入 `adb pair <设备弹窗给出的 IP 地址和端口>`,回车。 2. 输入 `<设备弹窗给出的六位配对码>`,回车。 3. 窗口出现 `Successfully paired to ` 等内容,同时设备上的弹窗自动消失,底部已配对的设备中出现计算机名称。 diff --git a/docs/zh-cn/manual/device/linux.md b/docs/zh-cn/manual/device/linux.md index a8bb1fd457..0407d50824 100644 --- a/docs/zh-cn/manual/device/linux.md +++ b/docs/zh-cn/manual/device/linux.md @@ -59,7 +59,6 @@ MAA WPF GUI 当前可以通过 Wine 运行。 #### 1. 安装 MAA 动态库 1. 在 [MAA 官网](https://maa.plus/) 下载 Linux 动态库并解压,或从软件源安装: - - AUR:[maa-assistant-arknights](https://aur.archlinux.org/packages/maa-assistant-arknights),按照安装后的提示编辑文件 - Nixpkgs: [maa-assistant-arknights](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-assistant-arknights/package.nix) @@ -75,7 +74,6 @@ MAA WPF GUI 当前可以通过 Wine 运行。 1. 找到 [`if asst.connect('adb.exe', '127.0.0.1:5554'):`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/b4fc3528decd6777441a8aca684c22d35d2b2574/src/Python/sample.py#L62) 一栏 2. ADB 工具调用 - - 如果模拟器使用 `Android Studio` 的 `avd` ,其自带 ADB 。可以直接在 `adb.exe` 一栏填写 ADB 路径,一般在 `$HOME/Android/Sdk/platform-tools/` 里面可以找到,例如: ```python @@ -85,7 +83,6 @@ MAA WPF GUI 当前可以通过 Wine 运行。 - 如果使用其他模拟器须先下载 ADB : `$ sudo apt install adb` 后填写路径或利用 `PATH` 环境变量直接填写 `adb` 即可。 3. 模拟器 ADB 路径获取 - - 可以直接使用 ADB 工具: `$ adb路径 devices` ,例如: ```shell diff --git a/docs/zh-cn/manual/faq.md b/docs/zh-cn/manual/faq.md index 36f9c5a5f7..e500a98e15 100644 --- a/docs/zh-cn/manual/faq.md +++ b/docs/zh-cn/manual/faq.md @@ -22,6 +22,7 @@ winget install "Microsoft.VCRedist.2015+.x64" --override "/repair /passive /nore - [Visual C++ 可再发行程序包](https://aka.ms/vs/17/release/vc_redist.x64.exe) - [.NET 桌面运行时 8](https://aka.ms/dotnet/8.0/windowsdesktop-runtime-win-x64.exe) + ::: ## 软件无法运行/闪退/报错 diff --git a/docs/zh-cn/manual/introduction/combat.md b/docs/zh-cn/manual/introduction/combat.md index 13890b26da..6be3719f43 100644 --- a/docs/zh-cn/manual/introduction/combat.md +++ b/docs/zh-cn/manual/introduction/combat.md @@ -8,7 +8,6 @@ icon: hugeicons:brain-02 ## 常规设置 - `吃理智药` + `吃源石` 和 `指定次数`、`指定材料` 三个选项为短路开关(或门),即达成三个选项中的任一条件,均会视为任务完成,停止刷理智。 - - `吃理智药` 指定补充几次理智(可能一次吃多瓶药)。 - `吃源石` 指定碎几颗石头(一次一颗),当仓库中有理智药时不会碎石。 - `指定次数` 指定刷多少次指定关卡(例如“刷 15 次后停止”)。 @@ -19,19 +18,19 @@ icon: hugeicons:brain-02 ::: details 例子 -| 吃理智药 | 吃源石 | 指定次数 | 指定材料 | 结果 | -| :------: | :----: | :------: | :------: | -------------------------------------------------------------------------------------------------------------------------------------- | -| | | | | 刷完现有理智即结束。 | -| 2 | | | | 先刷完现有理智,然后吃一次理智药,一共吃 `2` 次,刷完理智后结束。 | -| _999_ | 2 | | | 先刷完现有理智,并吃光理智药后,再碎石,一共碎 `2` 次,刷完理智后结束。 | -| | | 2 | | 刷 `2` 次选择的关卡即结束。 | -| | | | 2 | 掉落统计刷到 `2` 个指定的材料即结束。 | -| 2 | | 4 | | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。 | -| 2 | | | 4 | 在最多吃 `2` 次理智药的情况下,掉落统计刷到 `4` 个指定的材料即结束。 | -| 2 | | 4 | 8 | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。但如果在没刷完 `4` 次之前就获得了 `8` 个指定材料,则会提前结束。 | -| _999_ | 4 | 8 | 16 | 在最多吃光理智药并碎 `4` 次石头的情况下,刷 `8` 次选择的关卡即结束。但如果在没刷完 `8` 次之前就获得了 `16` 个指定材料,则会提前结束。 | -| | 2 | | | 先刷完现有理智,如果仓库中有理智药则结束,如果没有理智药则碎 `2` 次石,刷完理智后结束。_非 MAA GUI 行为_ | -| 2 | 4 | | | 先刷完现有理智,如果吃完 `2` 次理智药后还有理智药,则结束;如果吃完 ≤`2` 次理智药后没有理智药了,则继续碎 `4` 次石头,刷完理智后结束。_非 MAA GUI 行为_ | +| 吃理智药 | 吃源石 | 指定次数 | 指定材料 | 结果 | +| :------: | :----: | :------: | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| | | | | 刷完现有理智即结束。 | +| 2 | | | | 先刷完现有理智,然后吃一次理智药,一共吃 `2` 次,刷完理智后结束。 | +| _999_ | 2 | | | 先刷完现有理智,并吃光理智药后,再碎石,一共碎 `2` 次,刷完理智后结束。 | +| | | 2 | | 刷 `2` 次选择的关卡即结束。 | +| | | | 2 | 掉落统计刷到 `2` 个指定的材料即结束。 | +| 2 | | 4 | | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。 | +| 2 | | | 4 | 在最多吃 `2` 次理智药的情况下,掉落统计刷到 `4` 个指定的材料即结束。 | +| 2 | | 4 | 8 | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。但如果在没刷完 `4` 次之前就获得了 `8` 个指定材料,则会提前结束。 | +| _999_ | 4 | 8 | 16 | 在最多吃光理智药并碎 `4` 次石头的情况下,刷 `8` 次选择的关卡即结束。但如果在没刷完 `8` 次之前就获得了 `16` 个指定材料,则会提前结束。 | +| | 2 | | | 先刷完现有理智,如果仓库中有理智药则结束,如果没有理智药则碎 `2` 次石,刷完理智后结束。_非 MAA GUI 行为_ | +| 2 | 4 | | | 先刷完现有理智,如果吃完 `2` 次理智药后还有理智药,则结束;如果吃完 ≤`2` 次理智药后没有理智药了,则继续碎 `4` 次石头,刷完理智后结束。_非 MAA GUI 行为_ | ::: @@ -46,7 +45,6 @@ icon: hugeicons:brain-02 - 技能书、采购凭证、碳本第 5 关,必须输入 `CA-5` / `AP-5` / `SK-5`。 - 所有芯片本。必须输入完整关卡编号,如 `PR-A-1`。 - 剿灭模式支持以下传入值,必须使用对应的 Value: - - 当期剿灭:Annihilation - 切尔诺伯格:Chernobog@Annihilation - 龙门外环:LungmenOutskirts@Annihilation diff --git a/docs/zh-cn/manual/introduction/integrated-strategy.md b/docs/zh-cn/manual/introduction/integrated-strategy.md index f8b4714e0f..a9aafe79be 100644 --- a/docs/zh-cn/manual/introduction/integrated-strategy.md +++ b/docs/zh-cn/manual/introduction/integrated-strategy.md @@ -28,7 +28,7 @@ MAA 默认选择最新一期主题,可在 `自动肉鸽` - `肉鸽主题` 中 | 主题 | 难度 | 分队 | 职业组 | 干员 | | ------ | ------------- | --------------------------- | -------- | --------------- | | 傀影 | 正式调查·2 | 指挥分队 / 突击战术分队 | 取长补短 | 丰川祥子 / 棘刺 | -| 水月 | 波涛迭起·3~10 | 以人为本分队 / 心胜于物分队 | 稳扎稳打 | 维什戴尔 | +| 水月 | 波涛迭起·3~10 | 以人为本分队 / 心胜于物分队 | 稳扎稳打 | 维什戴尔 | | 萨米 | 挑战自然·4~10 | 特训分队 / 远程战术分队 | 稳扎稳打 | 维什戴尔 | | 萨卡兹 | 直面魂灵·4~10 | 蓝图测绘分队 / 远程战术分队 | 稳扎稳打 | 维什戴尔 | | 界园 | 请君入园·3~10 | 指挥分队 / 远程战术分队 | 稳扎稳打 | 维什戴尔 | @@ -41,7 +41,7 @@ MAA 默认选择最新一期主题,可在 `自动肉鸽` - `肉鸽主题` 中 | 水月 | `波涛迭起·4` 及更高难度招募六星干员希望消耗+1,使用 `心胜于物分队` 开局可能无法招募六星干员。
`以人为本分队` 适合账号练度较高的情况,`心胜于物分队` 需要赌运气。 | | 萨米 | `挑战自然·6` 及更高难度招募六星干员希望消耗+1,使用 `特训分队` 开局可能无法招募六星干员。 | | 萨卡兹 | `直面魂灵·15` 及更高难度招募六星干员希望消耗+1,若未升级 `历史重构` 中的 `蓝图测绘分队强化Ⅱ`,则使用 `蓝图测绘分队` 开局可能无法招募六星干员。
若选择 `蓝图测绘分队`,则会采用避战策略,可快速获取 `魂灵书签`,但基本无法通关结局。
当使用刷源石锭策略,开局分队为 `点刺成锭分队` 时,将会使用刷新商店策略加速流程。 | -| 界园 | `请君入园·15` 及更高难度招募六星干员希望消耗+1,使用 `指挥分队` 开局可能无法招募六星干员。
当难度选择为 `请君入园·3`及更高难度,使用刷源石锭策略,开局分队为 `指挥分队` 时,将会使用 `时光之末` 跳关策略加速流程。 | +| 界园 | `请君入园·15` 及更高难度招募六星干员希望消耗+1,使用 `指挥分队` 开局可能无法招募六星干员。
当难度选择为 `请君入园·3`及更高难度,使用刷源石锭策略,开局分队为 `指挥分队` 时,将会使用 `时光之末` 跳关策略加速流程。 | ::: diff --git a/docs/zh-cn/manual/newbie.md b/docs/zh-cn/manual/newbie.md index 358bb748bb..3c844c5c18 100644 --- a/docs/zh-cn/manual/newbie.md +++ b/docs/zh-cn/manual/newbie.md @@ -11,31 +11,31 @@ icon: ri:guide-fill 1. 确认系统版本 - MAA 在 Windows 下仅支持 10 和 11,旧版 Windows 请参阅[常见问题](./faq.md#系统问题)中的系统问题部分。 + MAA 在 Windows 下仅支持 10 和 11,旧版 Windows 请参阅[常见问题](./faq.md#系统问题)中的系统问题部分。 - 非 Windows 用户请参阅[模拟器及设备支持](./device/)。 + 非 Windows 用户请参阅[模拟器及设备支持](./device/)。 2. 下载正确的版本 - [MAA 官网](https://maa.plus/)一般会自动选择正确的版本架构,对于大多数阅读本文的用户来说,应为 Windows x64。 + [MAA 官网](https://maa.plus/)一般会自动选择正确的版本架构,对于大多数阅读本文的用户来说,应为 Windows x64。 3. 正确解压 - 确认解压完整,并确保将 MAA 解压到一个独立的文件夹中。请勿将 MAA 解压到如 `C:\`、`C:\Program Files\` 等需要 UAC 权限的路径。 + 确认解压完整,并确保将 MAA 解压到一个独立的文件夹中。请勿将 MAA 解压到如 `C:\`、`C:\Program Files\` 等需要 UAC 权限的路径。 4. 安装运行库 - MAA 需要 VCRedist x64 和 .NET 8,请运行 MAA 目录下的 `DependencySetup_依赖库安装.bat` 以安装。 + MAA 需要 VCRedist x64 和 .NET 8,请运行 MAA 目录下的 `DependencySetup_依赖库安装.bat` 以安装。 - 更多信息请参考[常见问题](./faq.md)置顶。 + 更多信息请参考[常见问题](./faq.md)置顶。 5. 确认模拟器支持 - 查阅[模拟器和设备支持](./device/),确认正在使用的模拟器支持情况。 + 查阅[模拟器和设备支持](./device/),确认正在使用的模拟器支持情况。 6. 正确设置模拟器分辨率 - 模拟器分辨率应为横屏的 `1280x720` 或 `1920x1080`;对于美服(YosterEN)玩家,必须为 `1920x1080`。 + 模拟器分辨率应为横屏的 `1280x720` 或 `1920x1080`;对于美服(YosterEN)玩家,必须为 `1920x1080`。 ## 初始配置 diff --git a/docs/zh-cn/protocol/callback-schema.md b/docs/zh-cn/protocol/callback-schema.md index 7b4a93cb2b..aa17fefa51 100644 --- a/docs/zh-cn/protocol/callback-schema.md +++ b/docs/zh-cn/protocol/callback-schema.md @@ -93,6 +93,7 @@ typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom - `adb` (string, required): `AsstConnect` 接口 `adb_path` 参数。 - `address` (string, required): `AsstConnect` 接口 `address` 参数。 - `config` (string, required): `AsstConnect` 接口 `config` 参数。 + ::: :::: @@ -136,6 +137,7 @@ typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom - `ret` (boolean, required): 实际调用的返回值。 - `cost` (number, required): 耗时,单位毫秒。 + ::: :::: diff --git a/docs/zh-cn/protocol/integrated-strategy-schema.md b/docs/zh-cn/protocol/integrated-strategy-schema.md index 47aac8e262..488493102d 100644 --- a/docs/zh-cn/protocol/integrated-strategy-schema.md +++ b/docs/zh-cn/protocol/integrated-strategy-schema.md @@ -61,7 +61,8 @@ icon: ri:game-fill 3. 请不要修改已经存在的 group 名称,以免在 MAA 更新时导致之前版本的作业无法使用 4. 请尽量不要新增 group,尽量将新添加进作业的单位按照用法纳入已经存在的 group - ::: + +::: ::: tip 默认仅招募精 1 55 级以上等级干员 @@ -94,60 +95,60 @@ icon: ri:game-fill 1. 已有群组介绍 - 以萨米肉鸽的作业为例:主要将干员分为了 + 以萨米肉鸽的作业为例:主要将干员分为了 - | 分组 | 主要考量 | 主要包括职业 | 举例干员 | - | :--- | :--- | :--- | :--- | - | **_地面阻挡_** | 站场和清杂 | 重装、近卫 | 奶盾、基石、羽毛笔、山、M3、令和稀音的召唤物、斑点、重装预备干员 | - | **_地面单切/处决者_** | 单独对战精英怪 | 处决者特种 | 史尔特尔、异德、麒麟 R 夜刀、M3、红 | - | **_高台 C_** | 常态和决战输出 | 狙击、术士 | 维什戴尔、逻各斯、假日威龙陈、澄闪 | - | **_高台输出_** | 对空和常态输出 | 狙击、术士 | 空弦、能天使、克洛丝、史都华德 | - | **_速狙_** | 物理输出,标准射程 | 狙击 | 艾拉、能天使、跃跃、克洛丝 | - | **_术师_** | 法术输出,标准射程 | 单法 | 艾雅法拉、逻各斯、史都华德 | - | **_辅助_** | 可以打到身后 1 格 | 辅助 | 塑心、铃兰、跃跃、梓兰 | - | **_狙击_** | 射程较远的高台 | 投掷手、攻城手 | 维什戴尔、提丰、早露 | - | **_奶_** | 治疗能力 | 治疗、辅助 | 凯尔希、浊心斯卡蒂、芙蓉、安赛尔 | - | **_单奶_** | 攻击范围纵深>=4 | 治疗 | 凯尔希、焰影苇草、纯烬艾雅法拉、芙蓉、安赛尔 | - | **_群奶_** | 攻击范围纵深<4,可以奶身后 | 治疗、辅助 | 夜莺、白面鸮、浊心斯卡蒂 | - | **_回费_** | 回复 cost | 先锋 | 桃金娘、伊内丝、芬、香草 | - | **_地刺_** | 无阻挡,在盾前提供输出或者减速 | 伏击客 | 归溟幽灵鲨、阿斯卡纶、狮蝎 | - | **_地面远程_** | 地面长手,可以在盾后输出 | 教官、领主 | 号角、帕拉斯、棘刺、银灰 | - | **_领主_** | 地面攻击范围纵深>4,可对空 | 要塞、领主 | 棘刺、银灰、仇白 | - | **_盾法_** | 攻击范围短,有一定承伤能力 | 阵法术师 | 林、卡涅利安 | - | **_炮灰_** | 吸收炮弹、再部署 | 特种、召唤物 | M3、红、桃金娘、预备干员 | - | **_大龙_** | 盾前承伤、紧靠阻挡方便合体 | 召唤物 | 令的小龙、涤火杰西卡的盾牌 | - | **_补给站_** | 给主 c 干员加快回转 | 召唤物 | 支援补给站、工匠类干员的召唤物 | - | **_无人机_** | 无视高台地面的治疗召唤物 | 召唤物 | 斯卡蒂的海嗣、赫默的无人机 | - | **_支援陷阱_** | 部署在地面的爆炸物 | 召唤物 | 支援雾机、支援轰隆隆 | - | **_障碍物_** | 不吃部署位吸引仇恨或者阻挡 | 召唤物 | 鸟笼、障碍物 | - | **_其他地面_** | 不希望被优先使用的地面 | 推拉、挡 1 先锋、剑豪 | 风笛、可颂 | - | **_高台预备/其他高台_** | 不希望被优先使用的高台 | 群法、链法、战术家 | 梓兰、预备干员 | + | 分组 | 主要考量 | 主要包括职业 | 举例干员 | + | :---------------------- | :----------------------------- | :-------------------- | :--------------------------------------------------------------- | + | **_地面阻挡_** | 站场和清杂 | 重装、近卫 | 奶盾、基石、羽毛笔、山、M3、令和稀音的召唤物、斑点、重装预备干员 | + | **_地面单切/处决者_** | 单独对战精英怪 | 处决者特种 | 史尔特尔、异德、麒麟 R 夜刀、M3、红 | + | **_高台 C_** | 常态和决战输出 | 狙击、术士 | 维什戴尔、逻各斯、假日威龙陈、澄闪 | + | **_高台输出_** | 对空和常态输出 | 狙击、术士 | 空弦、能天使、克洛丝、史都华德 | + | **_速狙_** | 物理输出,标准射程 | 狙击 | 艾拉、能天使、跃跃、克洛丝 | + | **_术师_** | 法术输出,标准射程 | 单法 | 艾雅法拉、逻各斯、史都华德 | + | **_辅助_** | 可以打到身后 1 格 | 辅助 | 塑心、铃兰、跃跃、梓兰 | + | **_狙击_** | 射程较远的高台 | 投掷手、攻城手 | 维什戴尔、提丰、早露 | + | **_奶_** | 治疗能力 | 治疗、辅助 | 凯尔希、浊心斯卡蒂、芙蓉、安赛尔 | + | **_单奶_** | 攻击范围纵深>=4 | 治疗 | 凯尔希、焰影苇草、纯烬艾雅法拉、芙蓉、安赛尔 | + | **_群奶_** | 攻击范围纵深<4,可以奶身后 | 治疗、辅助 | 夜莺、白面鸮、浊心斯卡蒂 | + | **_回费_** | 回复 cost | 先锋 | 桃金娘、伊内丝、芬、香草 | + | **_地刺_** | 无阻挡,在盾前提供输出或者减速 | 伏击客 | 归溟幽灵鲨、阿斯卡纶、狮蝎 | + | **_地面远程_** | 地面长手,可以在盾后输出 | 教官、领主 | 号角、帕拉斯、棘刺、银灰 | + | **_领主_** | 地面攻击范围纵深>4,可对空 | 要塞、领主 | 棘刺、银灰、仇白 | + | **_盾法_** | 攻击范围短,有一定承伤能力 | 阵法术师 | 林、卡涅利安 | + | **_炮灰_** | 吸收炮弹、再部署 | 特种、召唤物 | M3、红、桃金娘、预备干员 | + | **_大龙_** | 盾前承伤、紧靠阻挡方便合体 | 召唤物 | 令的小龙、涤火杰西卡的盾牌 | + | **_补给站_** | 给主 c 干员加快回转 | 召唤物 | 支援补给站、工匠类干员的召唤物 | + | **_无人机_** | 无视高台地面的治疗召唤物 | 召唤物 | 斯卡蒂的海嗣、赫默的无人机 | + | **_支援陷阱_** | 部署在地面的爆炸物 | 召唤物 | 支援雾机、支援轰隆隆 | + | **_障碍物_** | 不吃部署位吸引仇恨或者阻挡 | 召唤物 | 鸟笼、障碍物 | + | **_其他地面_** | 不希望被优先使用的地面 | 推拉、挡 1 先锋、剑豪 | 风笛、可颂 | + | **_高台预备/其他高台_** | 不希望被优先使用的高台 | 群法、链法、战术家 | 梓兰、预备干员 | - ::: tip - 地面阻挡主要考量干员防守的综合能力(有时候全杀了也是防守强的表现对吧),包括地面远程和领主组 + ::: tip + 地面阻挡主要考量干员防守的综合能力(有时候全杀了也是防守强的表现对吧),包括地面远程和领主组 - 奶主要考虑综合治疗能力,包括单奶和群奶,需要考虑攻击范围覆盖时要单独使用单奶(奶 4 格)或者群奶(奶身后) + 奶主要考虑综合治疗能力,包括单奶和群奶,需要考虑攻击范围覆盖时要单独使用单奶(奶 4 格)或者群奶(奶身后) - 高台输出只考虑输出能力,主要是狙击和术师职业的混杂排序,需要考虑输出类型、攻击范围等限制条件时单独使用速狙、术师、辅助、盾法 + 高台输出只考虑输出能力,主要是狙击和术师职业的混杂排序,需要考虑输出类型、攻击范围等限制条件时单独使用速狙、术师、辅助、盾法 - 夹子类召唤物因为数量较多,不要放在支援陷阱中,让 maa 自动部署效果比较好 - ::: + 夹子类召唤物因为数量较多,不要放在支援陷阱中,让 maa 自动部署效果比较好 + ::: 2. 需要特殊操作的群组 - 除了上面那些比较笼统的分组,我们有时候需要对一些干员或者干员种类进行一些定制的精细化操作,比如 + 除了上面那些比较笼统的分组,我们有时候需要对一些干员或者干员种类进行一些定制的精细化操作,比如 - | 分组 | 包括干员 | 主要特点 | - | :--- | :--- | :--- | - | 益达 | 维什戴尔 | 高台输出,优先部署可以减轻压力 | - | 棘刺 | 棘刺、号角 | 地面远程输出,傀影肉鸽有些图有非常适配的位置 | - | 召唤类 | 凯尔希、令、稀音 | 自带地面阻挡,有的图需要优先部署,召唤物可以当阻挡也可以当炮灰 | - | 情报官 | 晓歌、伊内丝 | 既可以回费、又可以侧面输出、还可以单切 | - | 浊心斯卡蒂 | 浊心斯卡蒂 | 低压时奶量尚可,但是范围特殊,一些图有比较适配的位置 | - | 焰苇 | 焰影苇草 | 萨米肉鸽常用开局干员,兼具治疗和输出,一些图有比较适配的位置 | - | 玛恩纳 | 玛恩纳、银灰 | 地面大范围决战输出,可以针对 boss 进行部署 | - | 史尔特尔 | 史尔特尔 | 由于精二后固定携带 3 技能,这时站场能力几乎为零,需要阻挡位的部署优先度极低 | - | 骰子 | 骰子 | 水月肉鸽中的骰子需要单独操作 | + | 分组 | 包括干员 | 主要特点 | + | :--------- | :--------------- | :-------------------------------------------------------------------------- | + | 益达 | 维什戴尔 | 高台输出,优先部署可以减轻压力 | + | 棘刺 | 棘刺、号角 | 地面远程输出,傀影肉鸽有些图有非常适配的位置 | + | 召唤类 | 凯尔希、令、稀音 | 自带地面阻挡,有的图需要优先部署,召唤物可以当阻挡也可以当炮灰 | + | 情报官 | 晓歌、伊内丝 | 既可以回费、又可以侧面输出、还可以单切 | + | 浊心斯卡蒂 | 浊心斯卡蒂 | 低压时奶量尚可,但是范围特殊,一些图有比较适配的位置 | + | 焰苇 | 焰影苇草 | 萨米肉鸽常用开局干员,兼具治疗和输出,一些图有比较适配的位置 | + | 玛恩纳 | 玛恩纳、银灰 | 地面大范围决战输出,可以针对 boss 进行部署 | + | 史尔特尔 | 史尔特尔 | 由于精二后固定携带 3 技能,这时站场能力几乎为零,需要阻挡位的部署优先度极低 | + | 骰子 | 骰子 | 水月肉鸽中的骰子需要单独操作 | ::: info 注意 目前固定将未识别到的地面干员归入倒数第二个编组后面(其他地面),未识别到的高台干员归入倒数第一个编组后面(其他高台) @@ -205,7 +206,7 @@ icon: ri:game-fill "groups": [ "奶" //(这里表示需要奶组的干员1名) ], - "threshold": 1 + "threshold": 1 } ... ] @@ -230,65 +231,65 @@ icon: ri:game-fill 4. 群组内干员各个字段的意思和脚本相关的逻辑 - ```json5 - { - "theme": "Phantom", - "priority": [ - "name": "地面阻挡", // 群组名(这里是地面阻挡组) - "doc": "标准线为1档(清杂能力或者站场能力比山强)>山>2档(阻挡>2,可自回)>斑点,站场能力小于斑点放到单切或者炮灰组", - // 带“doc”字段均为json内备注文档,对程序运行没有影响 - "opers": [ // 该包括哪些干员,有序,代表部署优先度 - { - "name": "百炼嘉维尔", // 干员名称(这里是百嘉,在组内第1位,表示需要部署地面阻挡组的时候,首先检测是不是百嘉) - "skill": 3, // 使用几技能(这里举例使用3技能) - "skill_usage": 2, // 技能使用模式,参考 战斗流程协议,不同在于,此处不写默认为1 - // (0为不自动使用,1为好了就用,2为好了就用x次(x通过"skill_times"字段设置),3暂时不支持) - "skill_times": 2, // 技能使用次数,默认为1,在"skill_usage"字段为2时生效 - "alternate_skill": 2, // 当没有指定技能时使用的备选技能,一般是6星干员未精二且精二后使用3技能时才需要指定(这里指没有3技能时使用2技能) - "alternate_skill_usage": 1, // 备选技能的技能使用模式(该字段尚未实现) - "alternate_skill_times": 1, // 备选技能的技能使用次数(该字段尚未实现) - "recruit_priority": 900, // 招募优先级,数字越大优先级越高,900以上属于看到必招,400以下招募优先级比一些关键干员精二优先度还低 - // 临时招募的干员优先度自动+600 - "promote_priority": 600, // 进阶优先级,数字越大优先级越高,900以上属于有希望就精二,400以下招募优先级低于招募普通三星干员 - // 小技巧:当你将招募优先度压低或者不写,拉高一些精二优先度,实际上就是在拉高临时招募到这些干员的精二优先度 - "is_key": true, // true为key(关键)干员,false或省略为非key干员。在阵容完备检测未通过时,仅招募key干员与0希望干员,保存希望。 - "is_start": true, // true为开局选择干员,false或省略为非开局干员。在队伍中没有start干员时,仅招募start干员与0希望干员 - // 与用户图形界面的开局干员绑定,且用户手动填写的干员会强制设为start干员 - "auto_retreat": 0, // 部署几秒后自动撤退,整数,大于 0 时生效,主要用于特种干员和投锋,由于肉鸽一般是2倍速,推荐设置为技能持续时间/2 - "recruit_priority_when_team_full": 850, // 无需单独设置,满足阵容完备度时,招募优先级,默认招募优先级-100 - "promote_priority_when_team_full": 850, // 无需单独设置,满足阵容完备度时,进阶优先级,默认精二优先级+300 - "recruit_priority_offsets": [ // 按当前阵容调控招募优先级 - { - "groups": [ // 需要哪些组满足条件,是按组计数,这些组里不要出现重复干员,否则会重复计数 - "凯尔希", - "地面阻挡", - "棘刺" - ], - "is_less": false, // 条件是大于还是小于, false是大于等于, true是小于等于,不写默认false - "threshold": 2, // 满足条件的数量,不写默认0 - "offset": -300 // 满足后对招募优先级的调整,不写默认0 - // (这里表示当 凯尔希, 地面阻挡, 棘刺 这三个群组中有2名以上干员时, 百炼嘉维尔的招募优先级减300) - } - ] - }, - ... - ], - ], - "team_complete_condition": [ - ... - ] - } - ``` + ```json5 + { + "theme": "Phantom", + "priority": [ + "name": "地面阻挡", // 群组名(这里是地面阻挡组) + "doc": "标准线为1档(清杂能力或者站场能力比山强)>山>2档(阻挡>2,可自回)>斑点,站场能力小于斑点放到单切或者炮灰组", + // 带“doc”字段均为json内备注文档,对程序运行没有影响 + "opers": [ // 该包括哪些干员,有序,代表部署优先度 + { + "name": "百炼嘉维尔", // 干员名称(这里是百嘉,在组内第1位,表示需要部署地面阻挡组的时候,首先检测是不是百嘉) + "skill": 3, // 使用几技能(这里举例使用3技能) + "skill_usage": 2, // 技能使用模式,参考 战斗流程协议,不同在于,此处不写默认为1 + // (0为不自动使用,1为好了就用,2为好了就用x次(x通过"skill_times"字段设置),3暂时不支持) + "skill_times": 2, // 技能使用次数,默认为1,在"skill_usage"字段为2时生效 + "alternate_skill": 2, // 当没有指定技能时使用的备选技能,一般是6星干员未精二且精二后使用3技能时才需要指定(这里指没有3技能时使用2技能) + "alternate_skill_usage": 1, // 备选技能的技能使用模式(该字段尚未实现) + "alternate_skill_times": 1, // 备选技能的技能使用次数(该字段尚未实现) + "recruit_priority": 900, // 招募优先级,数字越大优先级越高,900以上属于看到必招,400以下招募优先级比一些关键干员精二优先度还低 + // 临时招募的干员优先度自动+600 + "promote_priority": 600, // 进阶优先级,数字越大优先级越高,900以上属于有希望就精二,400以下招募优先级低于招募普通三星干员 + // 小技巧:当你将招募优先度压低或者不写,拉高一些精二优先度,实际上就是在拉高临时招募到这些干员的精二优先度 + "is_key": true, // true为key(关键)干员,false或省略为非key干员。在阵容完备检测未通过时,仅招募key干员与0希望干员,保存希望。 + "is_start": true, // true为开局选择干员,false或省略为非开局干员。在队伍中没有start干员时,仅招募start干员与0希望干员 + // 与用户图形界面的开局干员绑定,且用户手动填写的干员会强制设为start干员 + "auto_retreat": 0, // 部署几秒后自动撤退,整数,大于 0 时生效,主要用于特种干员和投锋,由于肉鸽一般是2倍速,推荐设置为技能持续时间/2 + "recruit_priority_when_team_full": 850, // 无需单独设置,满足阵容完备度时,招募优先级,默认招募优先级-100 + "promote_priority_when_team_full": 850, // 无需单独设置,满足阵容完备度时,进阶优先级,默认精二优先级+300 + "recruit_priority_offsets": [ // 按当前阵容调控招募优先级 + { + "groups": [ // 需要哪些组满足条件,是按组计数,这些组里不要出现重复干员,否则会重复计数 + "凯尔希", + "地面阻挡", + "棘刺" + ], + "is_less": false, // 条件是大于还是小于, false是大于等于, true是小于等于,不写默认false + "threshold": 2, // 满足条件的数量,不写默认0 + "offset": -300 // 满足后对招募优先级的调整,不写默认0 + // (这里表示当 凯尔希, 地面阻挡, 棘刺 这三个群组中有2名以上干员时, 百炼嘉维尔的招募优先级减300) + } + ] + }, + ... + ], + ], + "team_complete_condition": [ + ... + ] + } + ``` - ::: info 注意 - `recruit_priority_offsets`的`group`中的群组不要有重复干员 + ::: info 注意 + `recruit_priority_offsets`的`group`中的群组不要有重复干员 - `auto_retreat`设置后一般不需要再在作战计划中为其设置`retreat_plan` - ::: + `auto_retreat`设置后一般不需要再在作战计划中为其设置`retreat_plan` + ::: 5. 按照你的理解新增群组和干员 - 新增群组后,你可以从已有的群组中复制干员过来,参考大佬们已有的评分,在此基础上修改 + 新增群组后,你可以从已有的群组中复制干员过来,参考大佬们已有的评分,在此基础上修改 ## 肉鸽第二步——战斗逻辑 @@ -299,91 +300,89 @@ icon: ri:game-fill (在关卡名对应作战逻辑文件不存在时生效) 1. 根据地图上格子类型进行基本的战斗操作 + - MAA 会根据地图上的格子是蓝门还是红门,是高台还是地面,能不能被部署来进行基本的战斗操作 - - MAA 会根据地图上的格子是蓝门还是红门,是高台还是地面,能不能被部署来进行基本的战斗操作 + - MAA 仅根据地图名称或者编号决定使用哪份作业,不会判断地图的**普通**、**紧急**、**路网**、**密文板使用**等情况 - - MAA 仅根据地图名称或者编号决定使用哪份作业,不会判断地图的**普通**、**紧急**、**路网**、**密文板使用**等情况 + - MAA 不会判断**作战中地图上无法确定的格子的情况**,比如`驯兽小屋`的祭坛位置,`从众效应`是从左边还是从右边出怪 - - MAA 不会判断**作战中地图上无法确定的格子的情况**,比如`驯兽小屋`的祭坛位置,`从众效应`是从左边还是从右边出怪 - - 所以在后面,你需要尽量设计一套能够应付一个地图名**所有不同情况**(上面提到的几种情况)的战斗逻辑,小心被大家挂到 issue 上说这张图操作高血压哦(笑) + 所以在后面,你需要尽量设计一套能够应付一个地图名**所有不同情况**(上面提到的几种情况)的战斗逻辑,小心被大家挂到 issue 上说这张图操作高血压哦(笑) 2. MAA 的通用作战策略--堵蓝门 + 1. 地面干员会优先部署在蓝门的格子上(为什么是格子上,请往下看)或者周围,方向朝向红门(自动计算), - 1. 地面干员会优先部署在蓝门的格子上(为什么是格子上,请往下看)或者周围,方向朝向红门(自动计算), + 2. 优先部署地面,然后部署治疗干员和高台干员,一圈一圈的由蓝门向四周部署, - 2. 优先部署地面,然后部署治疗干员和高台干员,一圈一圈的由蓝门向四周部署, - - 3. 会不停的按照上面的逻辑部署可以部署的东西(干员、召唤物、支援物品等等) + 3. 会不停的按照上面的逻辑部署可以部署的东西(干员、召唤物、支援物品等等) ### 优化基本战斗策略 1. 蓝门替代方案 - 仅仅把干员堆在蓝门门口显然不太聪明,有些关卡有格子是一夫当关万夫莫开,防守在这里显然效率很高, + 仅仅把干员堆在蓝门门口显然不太聪明,有些关卡有格子是一夫当关万夫莫开,防守在这里显然效率很高, - 或者有些关卡有多个蓝门,MAA 不知道哪个蓝门对应哪个红门,也会胡乱部署, + 或者有些关卡有多个蓝门,MAA 不知道哪个蓝门对应哪个红门,也会胡乱部署, - 这个时候你需要打开 [地图 Wiki](https://map.ark-nights.com/areas?coord_override=MAA) 一边对着地图一边在脑海里指挥作战了 + 这个时候你需要打开 [地图 Wiki](https://map.ark-nights.com/areas?coord_override=MAA) 一边对着地图一边在脑海里指挥作战了 - 首先在`设置`里将`坐标展示`切换为`MAA` + 首先在`设置`里将`坐标展示`切换为`MAA` - 然后根据你的经验寻找需要优先防守的点的坐标和朝向(一般是朝向来怪的方向),写入到 json 的`"replacement_home"`里面 + 然后根据你的经验寻找需要优先防守的点的坐标和朝向(一般是朝向来怪的方向),写入到 json 的`"replacement_home"`里面 - ```json5 - { - "stage_name": "蓄水池", // 关卡名 - "replacement_home": [ // 重要防守点(蓝门替代点),至少需要填写1个 - { - "location": [ // 格子坐标,从地图wiki获得 - 6, - 4 - ], - "direction_Doc1": "优先朝向,但并不代表绝对是这个方向(算法自行判断)", - "direction_Doc2": "不填默认 none,即没有推荐方向,完全由算法自行判断", - "direction_Doc3": "none / left / right / up / down / 无 / 上 / 下 / 左 / 右", - "direction": "left" // (这里表示将干员优先部署到坐标6,4的格子朝左,周围自动部署的干员也尽量朝向左) - } - ], - ``` + ```json5 + { + "stage_name": "蓄水池", // 关卡名 + "replacement_home": [ // 重要防守点(蓝门替代点),至少需要填写1个 + { + "location": [ // 格子坐标,从地图wiki获得 + 6, + 4 + ], + "direction_Doc1": "优先朝向,但并不代表绝对是这个方向(算法自行判断)", + "direction_Doc2": "不填默认 none,即没有推荐方向,完全由算法自行判断", + "direction_Doc3": "none / left / right / up / down / 无 / 上 / 下 / 左 / 右", + "direction": "left" // (这里表示将干员优先部署到坐标6,4的格子朝左,周围自动部署的干员也尽量朝向左) + } + ], + ``` - ::: tip - 蓝门替代方案会在 `deploy_plan` 全部完成但待部署区仍有干员的情况下生效,逻辑同通用作战策略 - ::: + ::: tip + 蓝门替代方案会在 `deploy_plan` 全部完成但待部署区仍有干员的情况下生效,逻辑同通用作战策略 + ::: 2. 部署格子黑名单 - 有优先防守的点就有优先不部署干员的点,比如大火球经过的位置,boss 脚底下,一些不好输出的位置, + 有优先防守的点就有优先不部署干员的点,比如大火球经过的位置,boss 脚底下,一些不好输出的位置, - 这个时候我们引入了`"blacklist_location"`将不想让他部署干员的格子加到黑名单里 + 这个时候我们引入了`"blacklist_location"`将不想让他部署干员的格子加到黑名单里 - ::: info 注意 - 这里加入的格子,就算在后面的部署策略里面写进去的话,也是没法部署的 - ::: + ::: info 注意 + 这里加入的格子,就算在后面的部署策略里面写进去的话,也是没法部署的 + ::: - ```json5 - ... - "blacklist_location_Doc": "这里是用法举例,不是说蓄水池这个图需要 ban 这两个点", - "blacklist_location": [ // 禁止程序进行部署的位置 - [ - 0, - 0 - ], - [ - 1, - 1 - ] - ], - ``` + ```json5 + ... + "blacklist_location_Doc": "这里是用法举例,不是说蓄水池这个图需要 ban 这两个点", + "blacklist_location": [ // 禁止程序进行部署的位置 + [ + 0, + 0 + ], + [ + 1, + 1 + ] + ], + ``` 3. 其他地图策略 - 比如水月肉鸽中如果蓝门进怪了是不是要用骰子,缓解堆怪压力 + 比如水月肉鸽中如果蓝门进怪了是不是要用骰子,缓解堆怪压力 - ```json5 - "not_use_dice_Doc": "蓝门干员撤退时是否需要用骰子,不写默认false", - "not_use_dice": false, - ``` + ```json5 + "not_use_dice_Doc": "蓝门干员撤退时是否需要用骰子,不写默认false", + "not_use_dice": false, + ``` ### 还是高血压?是时候展现你真正的技术了——定制作战策略! @@ -395,132 +394,132 @@ icon: ri:game-fill 1. 使用各个群组部署干员 - ```json5 - "deploy_plan": [ // 部署逻辑,按从上到下、从左到右的顺序进行检索,并尝试部署找到的第一个干员,如果没有就跳过 - { - "groups": [ "百嘉", "基石", "地面C", "号角", "挡人先锋" ],//这一步从这些群组中寻找干员 - "location": [ 6, 4 ], //遍历百嘉群组、基石群组、地面C群组等等群组 - "direction": "left" //将找到的第一个干员部署到6,4这个坐标上并朝向左边 - }, //没找到就进行下一个部署操作 - { - "groups": [ "召唤" ], - "location": [ 6, 3 ], - "direction": "left" - }, - { - "groups": [ "单奶", "群奶" ], - "location": [ 6, 2 ], - "direction": "down" - } - ] - ``` + ```json5 + "deploy_plan": [ // 部署逻辑,按从上到下、从左到右的顺序进行检索,并尝试部署找到的第一个干员,如果没有就跳过 + { + "groups": [ "百嘉", "基石", "地面C", "号角", "挡人先锋" ],//这一步从这些群组中寻找干员 + "location": [ 6, 4 ], //遍历百嘉群组、基石群组、地面C群组等等群组 + "direction": "left" //将找到的第一个干员部署到6,4这个坐标上并朝向左边 + }, //没找到就进行下一个部署操作 + { + "groups": [ "召唤" ], + "location": [ 6, 3 ], + "direction": "left" + }, + { + "groups": [ "单奶", "群奶" ], + "location": [ 6, 2 ], + "direction": "down" + } + ] + ``` - ::: info 注意 - MAA 会将所有部署指令扁平化后,执行最优先级部署操作 - 例:在[6,4]部署[ "百嘉", "基石", "地面 C"],在[6,3]部署[ "基石", "地面 C"],那么 MAA 会将部署指令扁平化成附带坐标的[ "百嘉", "基石", "地面 C","基石", "地面 C"] - 如果在战斗中[6,4]位置的"百嘉"组干员倒下,手里有有可部署的“基石”组干员,会优先布置到[6,4]而不是[6,3] + ::: info 注意 + MAA 会将所有部署指令扁平化后,执行最优先级部署操作 + 例:在[6,4]部署[ "百嘉", "基石", "地面 C"],在[6,3]部署[ "基石", "地面 C"],那么 MAA 会将部署指令扁平化成附带坐标的[ "百嘉", "基石", "地面 C","基石", "地面 C"] + 如果在战斗中[6,4]位置的"百嘉"组干员倒下,手里有有可部署的“基石”组干员,会优先布置到[6,4]而不是[6,3] - 这意味着从宏观上来看,每次执行完部署动作之后都会从头开始检查可执行的策略(当前步骤的位置没有已经放置的干员,且待部署区有干员属于此步骤的干员组) - ::: + 这意味着从宏观上来看,每次执行完部署动作之后都会从头开始检查可执行的策略(当前步骤的位置没有已经放置的干员,且待部署区有干员属于此步骤的干员组) + ::: - ::: tip - 一些常用的干员组用法: + ::: tip + 一些常用的干员组用法: - 1.很多作业中主要防守点的组合是[ "地面阻挡", "处决者", "其他地面"],这意味着当主要抗伤位干员死了会尝试用处决者拖延 cd;当这个点生存压力过大时,考虑使用[ "重装","地面阻挡", "处决者", "炮灰", "其他地面"];盾后的点则可以优先盾后输出[ "地面远程","地面阻挡", "处决者", "其他地面"];单纯吸引仇恨 or 送死可以使用[ "炮灰", "障碍物", "其他地面"] + 1.很多作业中主要防守点的组合是[ "地面阻挡", "处决者", "其他地面"],这意味着当主要抗伤位干员死了会尝试用处决者拖延 cd;当这个点生存压力过大时,考虑使用[ "重装","地面阻挡", "处决者", "炮灰", "其他地面"];盾后的点则可以优先盾后输出[ "地面远程","地面阻挡", "处决者", "其他地面"];单纯吸引仇恨 or 送死可以使用[ "炮灰", "障碍物", "其他地面"] - 2.高台位组合常用[ "高台输出", "其他高台"],想要无论什么高台都可以放置可以使用[ "高台输出", "狙击", "辅助", "盾法", "其他高台"] + 2.高台位组合常用[ "高台输出", "其他高台"],想要无论什么高台都可以放置可以使用[ "高台输出", "狙击", "辅助", "盾法", "其他高台"] - 3.一些地面位置叔叔和地刺类干员都比较适合[ "玛恩纳", "地刺"] - ::: + 3.一些地面位置叔叔和地刺类干员都比较适合[ "玛恩纳", "地刺"] + ::: 2. 在某个时间点部署干员 - ::: tip - 适用于某些单切干员或者需要炮灰的使用场景 - ::: + ::: tip + 适用于某些单切干员或者需要炮灰的使用场景 + ::: - ```json5 - "deploy_plan": [ - { - "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 0, 3 ] // 该操作仅在击杀数为0-3时进行 - }, - { - "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 6, 10 ] - }, - ... - ] - ``` + ```json5 + "deploy_plan": [ + { + "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 0, 3 ] // 该操作仅在击杀数为0-3时进行 + }, + { + "groups": [ "异德", "刺客", "挡人先锋", "其他地面" ], + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 6, 10 ] + }, + ... + ] + ``` 3. 在某个时间点撤退干员 - ::: tip - 有时候炮灰过强站住场或者需要部署位腾挪阵容怎么办,撤退! + ::: tip + 有时候炮灰过强站住场或者需要部署位腾挪阵容怎么办,撤退! - 同一位置的部署和撤退命令的 condition 数字尽量不要重叠,否则会秒上秒下 - ::: + 同一位置的部署和撤退命令的 condition 数字尽量不要重叠,否则会秒上秒下 + ::: - ```json5 - "retreat_plan": [ // 在特定时间点撤退目标 - { - "location": [ 4, 1 ], - "condition": [ 7, 8 ] // 在击杀数为7-8时,撤去位置[4,1]的干员,没有就跳过 - } - ] - ``` + ```json5 + "retreat_plan": [ // 在特定时间点撤退目标 + { + "location": [ 4, 1 ], + "condition": [ 7, 8 ] // 在击杀数为7-8时,撤去位置[4,1]的干员,没有就跳过 + } + ] + ``` 4. 在某个时间点释放技能(to do) 5. 一些其他的字段(不推荐使用) - ```json5 - "role_order_Doc": "干员类型部署顺序,未写出部分以近卫,先锋,医疗,重装,狙击,术士,辅助,特种,召唤物的顺序补全,输入英文", - "role_order": [ // 不推荐使用,请配置deploy_plan字段 - "warrior", - "pioneer", - "medic", - "tank", - "sniper", - "caster", - "support", - "special", - "drone" - ], - "force_air_defense_when_deploy_blocking_num_Doc": "场上有10000个阻挡单位时就开始强制部署总共1个对空单位(填不填写均不影响正常部署逻辑),在此期间不禁止部署医疗单位(不写默认false)", - "force_air_defense_when_deploy_blocking_num": { // 不推荐使用,请配置deploy_plan字段 - "melee_num": 10000, - "air_defense_num": 1, - "ban_medic": false - }, - "force_deploy_direction_Doc": "这些点对某些职业强制部署方向", - "force_deploy_direction": [ // 不推荐使用,请配置deploy_plan字段 - { - "location": [ - 1, - 1 - ], - "role_Doc": "填入的职业适用强制方向", - "role": [ - "warrior", - "pioneer" - ], - "direction": "up" - }, - { - "location": [ - 3, - 1 - ], - "role": [ - "sniper" - ], - "direction": "left" - } - ], - ``` + ```json5 + "role_order_Doc": "干员类型部署顺序,未写出部分以近卫,先锋,医疗,重装,狙击,术士,辅助,特种,召唤物的顺序补全,输入英文", + "role_order": [ // 不推荐使用,请配置deploy_plan字段 + "warrior", + "pioneer", + "medic", + "tank", + "sniper", + "caster", + "support", + "special", + "drone" + ], + "force_air_defense_when_deploy_blocking_num_Doc": "场上有10000个阻挡单位时就开始强制部署总共1个对空单位(填不填写均不影响正常部署逻辑),在此期间不禁止部署医疗单位(不写默认false)", + "force_air_defense_when_deploy_blocking_num": { // 不推荐使用,请配置deploy_plan字段 + "melee_num": 10000, + "air_defense_num": 1, + "ban_medic": false + }, + "force_deploy_direction_Doc": "这些点对某些职业强制部署方向", + "force_deploy_direction": [ // 不推荐使用,请配置deploy_plan字段 + { + "location": [ + 1, + 1 + ], + "role_Doc": "填入的职业适用强制方向", + "role": [ + "warrior", + "pioneer" + ], + "direction": "up" + }, + { + "location": [ + 3, + 1 + ], + "role": [ + "sniper" + ], + "direction": "left" + } + ], + ``` ::: info 注意 当 maa 无法找到当前关卡对应的定制作战策略时,会自动执行通用作战策略 diff --git a/docs/zh-cn/protocol/integration.md b/docs/zh-cn/protocol/integration.md index 7977d00add..38ff645f94 100644 --- a/docs/zh-cn/protocol/integration.md +++ b/docs/zh-cn/protocol/integration.md @@ -22,8 +22,8 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha #### 返回值 - `AsstTaskId` - 若添加成功,返回该任务 ID, 可用于后续设置任务参数; - 若添加失败,返回 0 + 若添加成功,返回该任务 ID, 可用于后续设置任务参数; + 若添加失败,返回 0 #### 参数说明 @@ -42,7 +42,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ##### 任务类型一览 - `StartUp` - 开始唤醒 + 开始唤醒 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -68,7 +68,7 @@ B服:`张三`,可输入 `张三`、`张`、`三` :::: - `CloseDown` - 关闭游戏 + 关闭游戏 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -82,7 +82,7 @@ B服:`张三`,可输入 `张三`、`张`、`三` :::: - `Fight` - 刷理智 + 刷理智 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -222,7 +222,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `Infrast` - 基建换班 + 基建换班 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -242,7 +242,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟
设施名:`Mfg` | `Trade` | `Power` | `Control` | `Reception` | `Office` | `Dorm` | `Processing` | `Training` ::: -::: field name="drones" type="string" optional default="_NotUse" +::: field name="drones" type="string" optional default="\_NotUse" 无人机用途。`mode = 10000` 时该字段无效。
选项:`_NotUse` | `Money` | `SyntheticJade` | `CombatRecord` | `PureGold` | `OriginStone` | `Chip` @@ -282,8 +282,8 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `Mall` - 领取信用及商店购物。 - 会先有序的按 `buy_first` 购买一遍,再从左到右并避开 `blacklist` 购买第二遍,在信用溢出时则会无视黑名单从左到右购买第三遍直到不再溢出 + 领取信用及商店购物。 + 会先有序的按 `buy_first` 购买一遍,再从左到右并避开 `blacklist` 购买第二遍,在信用溢出时则会无视黑名单从左到右购买第三遍直到不再溢出 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -321,7 +321,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `Award` - 领取各种奖励 + 领取各种奖励 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -348,7 +348,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `Roguelike` - 无限刷肉鸽 + 无限刷肉鸽 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -502,7 +502,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 刷坍缩范式功能具体请参考 [肉鸽辅助协议](./integrated-strategy-schema.md#萨米肉鸽——坍缩范式) - `Copilot` - 自动抄作业 + 自动抄作业 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -519,7 +519,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 作业 JSON 请参考 [战斗流程协议](./copilot-schema.md) - `SSSCopilot` - 自动抄保全作业 + 自动抄保全作业 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -536,7 +536,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 保全作业 JSON 请参考 [保全派驻协议](./sss-schema.md) - `Depot` - 仓库识别 + 仓库识别 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -545,7 +545,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `OperBox` - 干员 box 识别 + 干员 box 识别 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -554,7 +554,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `Reclamation` - 生息演算 + 生息演算 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -563,9 +563,9 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 ::: field name="theme" type="string" optional default="Fire" 主题。
-`Fire` - *沙中之火* +`Fire` - _沙中之火_
-`Tales` - *沙洲遗闻* +`Tales` - _沙洲遗闻_ ::: ::: field name="mode" type="number" optional default="0" 模式。 @@ -590,7 +590,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `Custom` - 自定义任务 + 自定义任务 :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -602,7 +602,7 @@ Tag 等级(大于等于 3)和对应的希望招募时限,单位为分钟 :::: - `SingleStep` - 单步任务(目前仅支持战斗) + 单步任务(目前仅支持战斗) :::: field-group ::: field name="enable" type="boolean" optional default="true" @@ -652,7 +652,7 @@ bool ASSTAPI AsstSetTaskParams(AsstHandle handle, AsstTaskId id, const char* par #### 返回值 - `bool` - 返回是否设置成功 + 返回是否设置成功 #### 参数说明 @@ -663,7 +663,7 @@ bool ASSTAPI AsstSetTaskParams(AsstHandle handle, AsstTaskId id, const char* par ::: field name="task" type="AsstTaskId" required 任务 ID, `AsstAppendTask` 接口的返回值 ::: -::: field name="params" type="const char*" required +::: field name="params" type="const char\*" required 任务参数,json string,与 `AsstAppendTask` 接口相同。 未标注“不支持运行中设置”的字段都支持实时修改;否则若当前任务正在运行,会忽略对应的字段 ::: @@ -684,7 +684,7 @@ bool ASSTAPI AsstSetStaticOption(AsstStaticOptionKey key, const char* value); #### 返回值 - `bool` - 返回是否设置成功 + 返回是否设置成功 #### 参数说明 @@ -692,7 +692,7 @@ bool ASSTAPI AsstSetStaticOption(AsstStaticOptionKey key, const char* value); ::: field name="key" type="AsstStaticOptionKey" required 键 ::: -::: field name="value" type="const char*" required +::: field name="value" type="const char\*" required 值 ::: :::: @@ -716,7 +716,7 @@ bool ASSTAPI AsstSetInstanceOption(AsstHandle handle, AsstInstanceOptionKey key, #### 返回值 - `bool` - 返回是否设置成功 + 返回是否设置成功 #### 参数说明 @@ -727,7 +727,7 @@ bool ASSTAPI AsstSetInstanceOption(AsstHandle handle, AsstInstanceOptionKey key, ::: field name="key" type="AsstInstanceOptionKey" required 键 ::: -::: field name="value" type="const char*" required +::: field name="value" type="const char\*" required 值 ::: :::: diff --git a/docs/zh-cn/protocol/remote-control-schema.md b/docs/zh-cn/protocol/remote-control-schema.md index aa35da7cff..25378036f0 100644 --- a/docs/zh-cn/protocol/remote-control-schema.md +++ b/docs/zh-cn/protocol/remote-control-schema.md @@ -88,6 +88,7 @@ MAA 会以 1 秒的间隔持续轮询这个端点,尝试获取他要执行的 - Settings-[SettingsName] 型的任务的 type 的可选值为 Settings-ConnectionAddress, Settings-Stage1 - Settings 系列任务仍然是要按顺序执行的,并不会在收到任务的时候立刻执行,而是排在上一个任务的后面 - 多个立即执行的任务也会按下发顺序执行,只不过这些任务的执行速度都很快,通常来说,并不需要关注他们的顺序。 + ::: ## 汇报任务端点 diff --git a/docs/zh-cn/protocol/task-schema.md b/docs/zh-cn/protocol/task-schema.md index e521f1f0b3..a7cadec714 100644 --- a/docs/zh-cn/protocol/task-schema.md +++ b/docs/zh-cn/protocol/task-schema.md @@ -98,7 +98,7 @@ JSON 文件是不支持注释的,文本中的注释仅用于演示,请勿直 "highResolutionSwipeFix": false, // 可选项,是否启用高分辨率滑动修复 // 现阶段应该只有关卡导航未使用 unity 滑动方式所以需要开启 // 默认为 false - + /* 以下字段仅当 algorithm 为 MatchTemplate 时有效 */ "template": "xxx.png", // 可选项,要匹配的图片文件名,可以是字符串或字符串列表 @@ -112,7 +112,7 @@ JSON 文件是不支持注释的,文本中的注释仅用于演示,请勿直 // 例如将图片不需要识别的部分涂成黑色(灰度值为 0) // 然后设置为 [ 1, 255 ], 匹配的时候即忽略涂黑的部分 - "colorScales": [ // 当 method 为 HSVCount 或 RGBCount 时有效且必选,数色掩码范围。 + "colorScales": [ // 当 method 为 HSVCount 或 RGBCount 时有效且必选,数色掩码范围。 [ // list, 2>> / list> [23, 150, 40], // 结构为 [[lower1, upper1], [lower2, upper2], ...] [25, 230, 150] // 内层为 int 时是灰度, @@ -164,7 +164,7 @@ JSON 文件是不支持注释的,文本中的注释仅用于演示,请勿直 /* 以下字段仅当 algorithm 为 JustReturn,action 为 Input 时有效 */ "inputText": "A string text.", // 必选项,要输入的文字内容,以字符串的形式 - + /* 以下字段仅当 algorithm 为 FeatureMatch 时有效 */ "template": "xxx.png", // 可选项,要匹配的图片文件名,可以是字符串或字符串列表 @@ -190,11 +190,11 @@ JSON 文件是不支持注释的,文本中的注释仅用于演示,请勿直 | 符号 | 含义 | 实例 | | :---------: | :------------------------------------------------------: | :------------------------------------: | -| `@` | `@` 型任务 | `Fight@ReturnTo` | +| `@` | `@` 型任务 | `Fight@ReturnTo` | | `#`(单目) | 虚任务 | `#self` | | `#`(双目) | 虚任务 | `StartUpThemes#next` | | `*` | 重复多个任务 | `(ClickCornerAfterPRTS+ClickCorner)*5` | -| `+` | 任务列表合并(在 next 系列字段中同名任务只保留最靠前者) | `A+B` | +| `+` | 任务列表合并(在 next 系列字段中同名任务只保留最靠前者) | `A+B` | | `^` | 任务列表差(在前者但不在后者,顺序不变) | `(A+A+B+C)^(A+B+D)`(结果为 `C`) | 运算符 `@`, `#`, `*`, `+`, `^` 有优先级:`#`(单目)> `@` = `#`(双目)> `*` > `+` = `^`。 @@ -235,18 +235,18 @@ JSON 文件是不支持注释的,文本中的注释仅用于演示,请勿直 可以将虚任务分为**指令虚任务**(`#none` / `#self` / `#back`)和**字段虚任务**(`#next` 等)。 -| 虚任务类型 | 含义 | 简单示例 | -| :----------: | :----------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | -| none | 空任务 | 直接跳过1
`"A": {"next": ["#none", "T1"]}` 被解释为 `"A": {"next": ["T1"]}`
`"A#none + T1"` 被解释为 `"T1"` | -| self | 当前任务名 | `"A": {"next": ["#self"]}` 中的 `"#self"` 被解释为 `"A"`
`"B": {"next": ["A@B@C#self"]}` 中的 `"A@B@C#self"` 被解释为 `"B"`2 | -| back | # 前面的任务名 | `"A@B#back"` 被解释为 `"A@B"`
`"#back"` 直接出现则会被跳过3 | -| next, sub 等 | # 前任务名对应字段 | 以 `next` 为例:
`"A#next"` 被解释为 `Task.get("A")->next`
`"#next"` 直接出现则会被跳过 | +| 虚任务类型 | 含义 | 简单示例 | +| :----------: | :----------------: | :----------------------------------------------------------------------------------------------------------------------------------------: | +| none | 空任务 | 直接跳过1
`"A": {"next": ["#none", "T1"]}` 被解释为 `"A": {"next": ["T1"]}`
`"A#none + T1"` 被解释为 `"T1"` | +| self | 当前任务名 | `"A": {"next": ["#self"]}` 中的 `"#self"` 被解释为 `"A"`
`"B": {"next": ["A@B@C#self"]}` 中的 `"A@B@C#self"` 被解释为 `"B"`2 | +| back | # 前面的任务名 | `"A@B#back"` 被解释为 `"A@B"`
`"#back"` 直接出现则会被跳过3 | +| next, sub 等 | # 前任务名对应字段 | 以 `next` 为例:
`"A#next"` 被解释为 `Task.get("A")->next`
`"#next"` 直接出现则会被跳过 | -*Note1: `"#none"` 一般配合模板任务增加前缀的特性使用,或用在字段 `baseTask` 中避免多文件继承不必要的字段。* +_Note1: `"#none"` 一般配合模板任务增加前缀的特性使用,或用在字段 `baseTask` 中避免多文件继承不必要的字段。_ -*Note2: `"XXX#self"` 与 `"#self"` 含义相同。* +_Note2: `"XXX#self"` 与 `"#self"` 含义相同。_ -*Note3: 当几个任务有 `"next": [ "#back" ]` 时,`"T1@T2@T3"` 代表依次执行 `T3`, `T2`, `T1`。* +_Note3: 当几个任务有 `"next": [ "#back" ]` 时,`"T1@T2@T3"` 代表依次执行 `T3`, `T2`, `T1`。_ ### 多文件任务 @@ -259,86 +259,86 @@ JSON 文件是不支持注释的,文本中的注释仅用于演示,请勿直 - 派生任务示例(字段 `baseTask`) - 假设定义了如下两个任务: + 假设定义了如下两个任务: - ```json - "Return": { - "action": "ClickSelf", - "next": [ "Stop" ] - }, - "Return2": { - "baseTask": "Return" - }, - ``` + ```json + "Return": { + "action": "ClickSelf", + "next": [ "Stop" ] + }, + "Return2": { + "baseTask": "Return" + }, + ``` - 则 `"Return2"` 任务的参数会直接从 `"Return"` 任务继承,实际上包含以下参数: + 则 `"Return2"` 任务的参数会直接从 `"Return"` 任务继承,实际上包含以下参数: - ```json - "Return2": { - "algorithm": "MatchTemplate", // 直接继承 - "template": "Return2.png", // "任务名.png" - "action": "ClickSelf", // 直接继承 - "next": [ "Stop" ] // 直接继承,与 Template Task 相比这里没有前缀 - } - ``` + ```json + "Return2": { + "algorithm": "MatchTemplate", // 直接继承 + "template": "Return2.png", // "任务名.png" + "action": "ClickSelf", // 直接继承 + "next": [ "Stop" ] // 直接继承,与 Template Task 相比这里没有前缀 + } + ``` - `@` 型任务示例 - 假设定义了包含以下参数的任务 `"A"`: + 假设定义了包含以下参数的任务 `"A"`: - ```json - "A": { - "template": "A.png", - ..., - "next": [ "N1", "#back" ] - }, - ``` + ```json + "A": { + "template": "A.png", + ..., + "next": [ "N1", "#back" ] + }, + ``` - 如果任务 `"B@A"` 没有被直接定义,那么任务 `"B@A"` 实际上有以下参数: + 如果任务 `"B@A"` 没有被直接定义,那么任务 `"B@A"` 实际上有以下参数: - ```json - "B@A": { - "template": "A.png", - ..., - "next": [ "B@N1", "B#back" ] - } - ``` + ```json + "B@A": { + "template": "A.png", + ..., + "next": [ "B@N1", "B#back" ] + } + ``` - 如果任务 `"B@A"` 有定义 `"B@A": {}`,那么任务 `"B@A"` 实际上有以下参数: + 如果任务 `"B@A"` 有定义 `"B@A": {}`,那么任务 `"B@A"` 实际上有以下参数: - ```json - "B@A": { - "template": "B@A.png", - ..., - "next": [ "B@N1", "B#back" ] - } - ``` + ```json + "B@A": { + "template": "B@A.png", + ..., + "next": [ "B@N1", "B#back" ] + } + ``` - 虚任务示例 - ```json - { - "A": { "next": ["N1", "N2"] }, - "C": { "next": ["B@A#next"] }, + ```json + { + "A": { "next": ["N1", "N2"] }, + "C": { "next": ["B@A#next"] }, - "Loading": { - "next": ["#self", "#next", "#back"] - }, - "B": { - "next": ["Other", "B@Loading"] - } - } - ``` + "Loading": { + "next": ["#self", "#next", "#back"] + }, + "B": { + "next": ["Other", "B@Loading"] + } + } + ``` - 可以得到: + 可以得到: - ```cpp - Task.get("C")->next = { "B@N1", "B@N2" }; + ```cpp + Task.get("C")->next = { "B@N1", "B@N2" }; - Task.get("B@Loading")->next = { "B@Loading", "Other", "B" }; - Task.get("Loading")->next = { "Loading" }; - Task.get_raw("B@Loading")->next = { "B#self", "B#next", "B#back" }; - ``` + Task.get("B@Loading")->next = { "B@Loading", "Other", "B" }; + Task.get("Loading")->next = { "Loading" }; + Task.get_raw("B@Loading")->next = { "B#self", "B#next", "B#back" }; + ``` ### 注意事项 @@ -346,41 +346,41 @@ JSON 文件是不支持注释的,文本中的注释仅用于演示,请勿直 1. `@` 与 双目 `#` 的运算顺序导致的特例 - ```json - { - "A": { "next": ["N0"] }, - "B": { "next": ["A#next"] }, - "C@A": { "next": ["N1"] } - } - ``` + ```json + { + "A": { "next": ["N0"] }, + "B": { "next": ["A#next"] }, + "C@A": { "next": ["N1"] } + } + ``` - 以上这种情况, `"C@B" -> next`(即 `C@A#next`)为 `[ "N1" ]` 而不是 `[ "C@N0" ]`. + 以上这种情况, `"C@B" -> next`(即 `C@A#next`)为 `[ "N1" ]` 而不是 `[ "C@N0" ]`. 2. `@` 与 `+` 的运算顺序导致的特例 - ```json - { - "A": { "next": ["#back + N0"] }, - "B@A": {} - } - ``` + ```json + { + "A": { "next": ["#back + N0"] }, + "B@A": {} + } + ``` - 以上这种情况, + 以上这种情况, - ```cpp - Task.get("A")->next = { "N0" }; + ```cpp + Task.get("A")->next = { "N0" }; - Task.get_raw("B@A")->next = { "B#back + N0" }; - Task.get("B@A")->next = { "B", "N0" }; // 注意不是 [ "B", "B@N0" ] - ``` + Task.get_raw("B@A")->next = { "B#back + N0" }; + Task.get("B@A")->next = { "B", "N0" }; // 注意不是 [ "B", "B@N0" ] + ``` - 事实上,你可以用这个特性来避免添加不必要的前缀,只需要定义 + 事实上,你可以用这个特性来避免添加不必要的前缀,只需要定义 - ```json - { - "A": { "next": ["#none + N0"] } - } - ``` + ```json + { + "A": { "next": ["#none + N0"] } + } + ``` ## 运行时修改任务 diff --git a/docs/zh-cn/readme.md b/docs/zh-cn/readme.md index adfca30640..b8654c5f1e 100644 --- a/docs/zh-cn/readme.md +++ b/docs/zh-cn/readme.md @@ -26,7 +26,7 @@ MAA 的意思是 MAA Assistant Arknights 基于图像识别技术,一键完成全部日常任务! -绝赞更新中 ✿✿ヽ(°▽°)ノ✿ +绝赞更新中 ✿✿ヽ(°▽°)ノ✿ ::: @@ -47,7 +47,7 @@ MAA 的意思是 MAA Assistant Arknights - 选择作业 JSON 文件,自动抄作业, [视频演示](https://www.bilibili.com/video/BV1H841177Fk/) - 支持 C, Python, Java, Rust, Golang, Java HTTP, Rust HTTP 等多种接口,方便集成调用,自定义你的 MAA! -话不多说,看图! +话不多说,看图! + 2. 把 “僅 master 分支” 這個選項去掉,然後點擊 Create Fork - + 3. 接下來來到了你的個人倉庫,可以看到標題是 “你的名字/MaaAssistantArknights”,下面一行小字 forked from MaaAssistantArknights/MaaAssistantArknights (複製自 MAA 主倉庫) - + 4. 找到你要改的檔案,可以點 “Go to file” 進行全局搜尋,也可以直接在下面的資料夾裡翻(如果你知道檔案在哪的話) - + 5. 打開檔案後,直接點擊檔案右上角的 ✏️ 進行編輯 - + 6. 開改!(當然如果是資源檔案這種,我們建議先在你電腦上的 MAA 資料夾裡測試修改,確認沒問題了再貼上到網頁上,避免改錯了) 7. 改完了,翻到最下面,寫一下你改了啥 - + - + 8. 還有第二個檔案要改的?改完了發現弄錯了想再改改?都沒關係!重複 5-8 即可! 9. 全改好了進行 PR !直接點 **個人倉庫** 裡的 Pull Request 標籤頁 - 如果有 Compare & Pull Request 按鈕,那最好,直接點他!如果沒有也不用著急,點下面的 New Pull Request 也是一樣的(請看步驟 11) + 如果有 Compare & Pull Request 按鈕,那最好,直接點他!如果沒有也不用著急,點下面的 New Pull Request 也是一樣的(請看步驟 11) - + 10. 這時候來到了主倉庫,請核對一下你要 PR 的是否確認。 - 如圖中,中間有個向左的箭頭,是將右邊的 個人姓名/MAA 的 dev 分支,申請合併到 主倉庫/MAA 的 dev 分支。 + 如圖中,中間有個向左的箭頭,是將右邊的 個人姓名/MAA 的 dev 分支,申請合併到 主倉庫/MAA 的 dev 分支。 11. 等待 MAA Team 的大佬們審核吧!當然他們也可能會提意見 - 👇 比如(純屬娛樂切勿當真) + 👇 比如(純屬娛樂切勿當真) + { + light: 'images/zh-cn/pr-tutorial/pr-11-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-11-dark.png' + } + ]" /> 12. 如果大佬們說要再修改一些小問題的話,回到 **你的個人倉庫**,切換到先前的 dev 分支,重複 步驟 3-9 即可! - 注意不需要操作步驟 2(重新 fork),也不需要操作步驟 10(重新 Pull Request),你目前的 Pull Request 仍處於待審核狀態,後續的修改會直接進入到這個 Pull Request 中 - 👇 比如可以看到最下面多了一條 “重新修改演示” 的內容 + 注意不需要操作步驟 2(重新 fork),也不需要操作步驟 10(重新 Pull Request),你目前的 Pull Request 仍處於待審核狀態,後續的修改會直接進入到這個 Pull Request 中 + 👇 比如可以看到最下面多了一條 “重新修改演示” 的內容 + { + light: 'images/zh-cn/pr-tutorial/pr-12-light.png', + dark: 'images/zh-cn/pr-tutorial/pr-12-dark.png' + } + ]" /> 13. 等大佬們審批通過,就全部完成啦!**版本發布後**,你的 GitHub 頭像將會自動進入到貢獻者列表名單中,非常感謝各位的無私奉獻! ~~怎麽全是二次元啊,哦我也是啊,那沒事了~~ ::: tip 貢獻 / 參與者 - 感謝所有參與到開發 / 測試中的朋友們,是大家的幫助讓 MAA 越來越好! (*´▽`)ノノ + 感謝所有參與到開發 / 測試中的朋友們,是大家的幫助讓 MAA 越來越好! (\*´▽`)ノノ [![Contributors](https://contributors-img.web.app/image?repo=MaaAssistantArknights/MaaAssistantArknights&max=105&columns=15)](https://github.com/MaaAssistantArknights/MaaAssistantArknights/graphs/contributors) ::: @@ -194,7 +195,7 @@ icon: mingcute:git-pull-request-fill ::: warning 這個操作會強制將你的個人倉庫同步到和主倉庫一模一樣的狀態,這是最簡單粗暴但行之有效的解決衝突的方法。但如果你的個人倉庫已經有額外的編輯了,會被直接刪掉! ::: - 如果確定不會造成衝突,請使用右側綠色的 `Update Branch` 按鈕 + 如果確定不會造成衝突,請使用右側綠色的 `Update Branch` 按鈕 如果你不清楚 / 不 care 我上面說的這一大堆,也請點擊左側的按鈕 diff --git a/docs/zh-tw/develop/vsc-ext-tutorial.md b/docs/zh-tw/develop/vsc-ext-tutorial.md index cc4a52340d..684c8c8767 100644 --- a/docs/zh-tw/develop/vsc-ext-tutorial.md +++ b/docs/zh-tw/develop/vsc-ext-tutorial.md @@ -5,8 +5,8 @@ icon: iconoir:code-brackets # 專用 VSCode 插件教學 -* [插件商店](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) -* [倉庫](https://github.com/neko-para/maa-support-extension) +- [插件商店](https://marketplace.visualstudio.com/items?itemName=nekosu.maa-support) +- [倉庫](https://github.com/neko-para/maa-support-extension) ## 安裝 @@ -60,10 +60,10 @@ icon: iconoir:code-brackets 插件支持定時掃描並分析所有任務. -* 檢查是否有重名任務定義 -* 檢查是否有未知任務引用 -* 檢查是否有未知圖片引用 -* 檢查單個任務中是否有重複的任務引用 +- 檢查是否有重名任務定義 +- 檢查是否有未知任務引用 +- 檢查是否有未知圖片引用 +- 檢查單個任務中是否有重複的任務引用 #### 多路徑資源支持 @@ -83,11 +83,11 @@ icon: iconoir:code-brackets > 使用 `Ctrl+Shift+P` (MacOS 上則是 `Command+Shift+P`) 呼出命令面板 -* 選擇並連接控制器後, 可使用 `截圖` 按鈕直接獲取截圖 -* 可使用 `上傳` 按鈕手動上傳 -* 按住 `Ctrl` 鍵, 框選需要裁剪的區域 -* 使用滾輪可進行縮放 -* 裁剪完成後, 使用 `下載` 按鈕, 可自動將裁剪結果保存到啟用資源的最頂層的圖片目錄 +- 選擇並連接控制器後, 可使用 `截圖` 按鈕直接獲取截圖 +- 可使用 `上傳` 按鈕手動上傳 +- 按住 `Ctrl` 鍵, 框選需要裁剪的區域 +- 使用滾輪可進行縮放 +- 裁剪完成後, 使用 `下載` 按鈕, 可自動將裁剪結果保存到啟用資源的最頂層的圖片目錄 ### 底部狀態欄 diff --git a/docs/zh-tw/manual/connection.md b/docs/zh-tw/manual/connection.md index 873bc7eb97..07f2b5f27f 100644 --- a/docs/zh-tw/manual/connection.md +++ b/docs/zh-tw/manual/connection.md @@ -55,7 +55,6 @@ icon: mdi:plug ::: details 備選方案 - 方案 1 : 使用 ADB 命令檢視模擬器埠 - 1. 啟動**一個**模擬器,並確保沒有其他安卓裝置連接在此電腦上。 2. 在存放有 ADB 可執行檔案的資料夾中啟動終端。 3. 執行以下命令。 @@ -78,7 +77,6 @@ icon: mdi:plug 使用 `127.0.0.1:<埠>` 或 `emulator-<四位數字>` 作為連接地址。 - 方案 2 : 查詢已建立的 ADB 連接 - 1. 執行方案 1。 2. 按下 `Win+S` 開啟搜尋欄,輸入 `資源監視器` 並開啟。 3. 切換到 `網路` 索引標籤,在 `接聽連接埠` 的名稱列中查詢模擬器程式名,如 `HD-Player.exe`。 @@ -123,7 +121,6 @@ MAA 現在會嘗試從登錄檔中讀取 `bluestacks.conf` 的儲存位置,當 ::: 1. 在藍疊模擬器的資料目錄下找到 `bluestacks.conf` 這個檔案 - - 國際版預設路徑為 `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` - 中國版預設路徑為 `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` diff --git a/docs/zh-tw/manual/device/android.md b/docs/zh-tw/manual/device/android.md index eaf85b839d..06d58a175a 100644 --- a/docs/zh-tw/manual/device/android.md +++ b/docs/zh-tw/manual/device/android.md @@ -16,6 +16,7 @@ icon: mingcute:android-fill 3. 由於 MAA 僅支援 `16:9` 比例的解析度,所以非 `16:9` 或 `9:16` 螢幕比例的設備需要強制修改解析度,這包含大多數現代設備。若被連接設備螢幕解析度比例原生為 `16:9` 或 `9:16`,則可跳過 `更改解析度` 部分。 4. 請將設備導航方式切換為除 `全面屏手勢` 以外的方式,如 `經典導航鍵` 等以避免誤操作。 5. 請將遊戲內設定中的 `異形屏UI適配` 一項調整為 0 以避免任務出錯。 + ::: ::: tip @@ -35,7 +36,6 @@ icon: mingcute:android-fill ``` - 成功執行後會顯示已連接 `USB 調試` 設備的信息。 - - 連接成功的例子: ```bash @@ -117,7 +117,6 @@ icon: mingcute:android-fill ``` 2. 將第一個檔案重命名為 `startup.bat`,第二個檔案重命名為 `finish.bat`。 - - 如果重命名後沒有彈出修改擴展名的二次確認對話框,且檔案圖示沒有變化,請自行搜尋“Windows 如何顯示檔案擴展名”。 3. 在 MAA 的 `設定` - `連接設定` - `開始前腳本` 和 `結束後腳本` 中分別填入 `startup.bat` 和 `finish.bat`。 @@ -148,7 +147,6 @@ icon: mingcute:android-fill ``` 2. 查看設備 IP 地址。 - - 進入手機 `設定` - `WLAN`,點擊當前已連接的無線網路查看 IP 地址。 - 各類品牌設備設定位置不同,請自行查找。 @@ -164,7 +162,6 @@ icon: mingcute:android-fill 1. 進入手機開發者選項,點擊 `無線調試` 並開啟,點擊確定,點擊 `使用配對碼配對設備`,在配對完成前不要關閉出現的彈窗。 2. 進行配對。 - 1. 在命令提示符中輸入 `adb pair <設備彈窗給出的 IP 地址和埠>`,按回車。 2. 輸入 `<設備彈窗給出的六位配對碼>`,按回車。 3. 視窗出現 `Successfully paired to ` 等內容,同時設備上的彈窗自動消失,底部已配對的設備中出現計算機名稱。 diff --git a/docs/zh-tw/manual/device/linux.md b/docs/zh-tw/manual/device/linux.md index 20b1514e85..c7f746fabe 100644 --- a/docs/zh-tw/manual/device/linux.md +++ b/docs/zh-tw/manual/device/linux.md @@ -2,6 +2,7 @@ order: 3 icon: teenyicons:linux-alt-solid --- + # Linux 模擬器與容器 ## 準備工作 @@ -17,7 +18,6 @@ icon: teenyicons:linux-alt-solid #### 1. 安裝 MAA 動態庫 1. 在 [MAA 官網](https://maa.plus/) 下載 Linux 動態庫並解壓,或從軟體源安裝: - - AUR:[maa-assistant-arknights](https://aur.archlinux.org/packages/maa-assistant-arknights),按照安裝後的提示編輯檔案 - Nixpkgs: [maa-assistant-arknights](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ma/maa-assistant-arknights/package.nix) @@ -33,30 +33,28 @@ icon: teenyicons:linux-alt-solid 1. 找到 [`if asst.connect('adb.exe', '127.0.0.1:5554'):`](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/722f0ddd4765715199a5dc90ea1bec2940322344/src/Python/sample.py#L48) 一欄 2. `adb` 工具調用 - - 如果模擬器使用 `Android Studio` 的 `avd` ,其內建 `adb` 。可以直接在 `adb.exe` 一欄填寫 `adb` 路徑,一般在 `$HOME/Android/Sdk/platform-tools/` 裡面可以找到,例如: - ```python - if asst.connect("/home/foo/Android/Sdk/platform-tools/adb", "模擬器的 adb 地址"): - ``` + ```python + if asst.connect("/home/foo/Android/Sdk/platform-tools/adb", "模擬器的 adb 地址"): + ``` - 如果使用其他模擬器須先下載 `adb` : `$ sudo apt install adb` 後填寫路徑或利用 `PATH` 環境變量直接填寫 `adb` 即可 3. 模擬器 `adb` 路徑獲取 - - 可以直接使用 adb 工具: `$ adb路徑 devices` ,例如: - ```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 + ``` - 返回的 `emulator-5554` 就是模擬器的 adb 地址,覆蓋掉 `127.0.0.1:5555` ,例如: - ```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. 這時候可以測試下: `$ python3 sample.py` ,如果返回 `連接成功` 則基本成功了 @@ -70,11 +68,11 @@ icon: teenyicons:linux-alt-solid 必選配置: 16:9 的螢幕解析度,且解析度需大於 720p -推薦配置: x86\_64 的框架 (R - 30 - x86\_64 - Android 11.0) 配合 MAA 的 Linux x64 動態庫 +推薦配置: x86_64 的框架 (R - 30 - x86_64 - Android 11.0) 配合 MAA 的 Linux x64 動態庫 ### ⚠️ [Genymotion](https://www.genymotion.com/) -高版本安卓內建 x86\_64 框架,輕量但是執行明日方舟時易閃退 +高版本安卓內建 x86_64 框架,輕量但是執行明日方舟時易閃退 暫未嚴格測試, adb 功能和路徑獲取沒有問題 diff --git a/docs/zh-tw/manual/device/macos.md b/docs/zh-tw/manual/device/macos.md index 3355524791..7a9f105311 100644 --- a/docs/zh-tw/manual/device/macos.md +++ b/docs/zh-tw/manual/device/macos.md @@ -2,6 +2,7 @@ order: 2 icon: basil:apple-solid --- + # Mac 模擬器 ::: tip diff --git a/docs/zh-tw/manual/faq.md b/docs/zh-tw/manual/faq.md index 51ead0a484..6d57ad0a81 100644 --- a/docs/zh-tw/manual/faq.md +++ b/docs/zh-tw/manual/faq.md @@ -55,11 +55,11 @@ winget install "Microsoft.VCRedist.2015+.x64" --override "/repair /passive /nore 對於 Windows 7,在安裝上文提到的兩個運行庫之前,還需檢查以下補丁是否已安裝: - 1. [Windows 7 Service Pack 1](https://support.microsoft.com/zh-cn/windows/b3da2c0f-cdb6-0572-8596-bab972897f61) - 2. SHA-2 代碼簽名修補程式: - - KB4474419:[下載連結 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)、[下載連結 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu) - - KB4490628:[下載連結 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)、[下載連結 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):[下載連結 1](https://catalog.s.download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu)、[下載連結 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/zh-cn/windows/b3da2c0f-cdb6-0572-8596-bab972897f61) +2. SHA-2 代碼簽名修補程式: + - KB4474419:[下載連結 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu)、[下載連結 2](http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu) + - KB4490628:[下載連結 1](https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu)、[下載連結 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):[下載連結 1](https://catalog.s.download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu)、[下載連結 2](http://download.windowsupdate.com/msdownload/update/software/ftpk/2013/02/windows6.1-kb2670838-x64_9f667ff60e80b64cbed2774681302baeaf0fc6a6.msu) ##### .NET 8 應用在 Windows 7 上運行異常的緩解措施 [#8238](https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/8238) @@ -88,21 +88,20 @@ winget install "Microsoft.VCRedist.2015+.x64" --override "/repair /passive /nore 針對模擬器單開情況,參考各個模擬器文件和網易遊戲高級遊戲開發工程師@趙青青的[博客](https://www.cnblogs.com/zhaoqingqing/p/15238464.html),常見安卓模擬器的 adb 通訊埠如下: - |模擬器|主模擬器預設通訊埠| - |-|:-:| - |網易 MuMu 模擬器 6/X|7555| - |網易 MuMu 模擬器 12|16384| - |夜神安卓模擬器|62001| - |逍遙安卓模擬器|21503| - |藍疊安卓模擬器|5555| - |雷電安卓模擬器 9|5555 / emulator-5554| + | 模擬器 | 主模擬器預設通訊埠 | + | -------------------- | :------------------: | + | 網易 MuMu 模擬器 6/X | 7555 | + | 網易 MuMu 模擬器 12 | 16384 | + | 夜神安卓模擬器 | 62001 | + | 逍遙安卓模擬器 | 21503 | + | 藍疊安卓模擬器 | 5555 | + | 雷電安卓模擬器 9 | 5555 / emulator-5554 | - 純數字的預設通訊埠可以直接使用 `127.0.0.1:[port]` 來連接,雷電模擬器進行了封裝,也可以使用 `emulator-5554` 進行連接。 + 純數字的預設通訊埠可以直接使用 `127.0.0.1:[port]` 來連接,雷電模擬器進行了封裝,也可以使用 `emulator-5554` 進行連接。 - 在 Windows 與 Mac 的 `設定` - `連接設定` - `連接地址` 配置中,如果有情況需要修改則可以參照上表。 + 在 Windows 與 Mac 的 `設定` - `連接設定` - `連接地址` 配置中,如果有情況需要修改則可以參照上表。 - 多開情況 - - 夜神模擬器第一個設備通訊埠為 `62001` ,第二個通訊埠從 `62025` 開始遞增。 - 網易 MuMu 模擬器 12 版本多開時 adb 通訊埠無規律,可以通過點擊 MuMu 多開器 12,啟動需要執行的模擬器,點擊右上角的 ADB 圖示,即可查看目前正在執行的模擬器 adb 通訊埠資訊。 - 雷電模擬器從 9 版本開始,模擬器 adb 從本地通訊埠 `5555` 開始逐個遞增 2 ,比如第二個模擬器本地通訊埠為 `5557`。 @@ -166,9 +165,8 @@ MAA 現在會嘗試從註冊表中讀取 `bluestacks.conf` 的儲存位置,當 ::: 1. 在藍疊模擬器的數據目錄下找到 `bluestacks.conf` 這個檔案 - - - 國際版預設路徑為 `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` - - 中國內地版預設路徑為 `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` + - 國際版預設路徑為 `C:\ProgramData\BlueStacks_nxt\bluestacks.conf` + - 中國內地版預設路徑為 `C:\ProgramData\BlueStacks_nxt_cn\bluestacks.conf` 2. 如果是第一次使用,請開啟一次 MAA,會在 MAA 的 `config` 目錄下產生 `gui.json`。 diff --git a/docs/zh-tw/manual/introduction/combat.md b/docs/zh-tw/manual/introduction/combat.md index 7aba799700..1f8fef3063 100644 --- a/docs/zh-tw/manual/introduction/combat.md +++ b/docs/zh-tw/manual/introduction/combat.md @@ -12,7 +12,6 @@ This page is outdated and maybe still in Simplified Chinese. Translation is need ## 常规设置 - `吃理智药` + `吃源石` 和 `指定次数`、`指定材料` 三个选项为短路开关(或门),即达成三个选项中的任一条件,均会视为任务完成,停止刷理智。 - - `吃理智药` 指定补充几次理智(可能一次吃多瓶药)。 - `吃源石` 指定碎几颗石头(一次一颗),当仓库中有理智药时不会碎石。 - `指定次数` 指定刷多少次指定关卡(例如“刷 15 次后停止”)。 @@ -23,19 +22,19 @@ This page is outdated and maybe still in Simplified Chinese. Translation is need ::: details 例子 -| 吃理智药 | 吃源石 | 指定次数 | 指定材料 | 结果 | -| :------: | :----: | :------: | :------: | -------------------------------------------------------------------------------------------------------------------------------------- | -| | | | | 刷完现有理智即结束。 | -| 2 | | | | 先刷完现有理智,然后吃一次理智药,一共吃 `2` 次,刷完理智后结束。 | -| _999_ | 2 | | | 先刷完现有理智,并吃光理智药后,再碎石,一共碎 `2` 次,刷完理智后结束。 | -| | | 2 | | 刷 `2` 次选择的关卡即结束。 | -| | | | 2 | 掉落统计刷到 `2` 个指定的材料即结束。 | -| 2 | | 4 | | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。 | -| 2 | | | 4 | 在最多吃 `2` 次理智药的情况下,掉落统计刷到 `4` 个指定的材料即结束。 | -| 2 | | 4 | 8 | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。但如果在没刷完 `4` 次之前就获得了 `8` 个指定材料,则会提前结束。 | -| _999_ | 4 | 8 | 16 | 在最多吃光理智药并碎 `4` 次石头的情况下,刷 `8` 次选择的关卡即结束。但如果在没刷完 `8` 次之前就获得了 `16` 个指定材料,则会提前结束。 | -| | 2 | | | 先刷完现有理智,如果仓库中有理智药则结束,如果没有理智药则碎 `2` 次石,刷完理智后结束。_非 MAA GUI 行为_ | -| 2 | 4 | | | 先刷完现有理智,如果吃完 `2` 次理智药后还有理智药,则结束;如果吃完 ≤`2` 次理智药后没有理智药了,则继续碎 `4` 次石头,刷完理智后结束。_非 MAA GUI 行为_ | +| 吃理智药 | 吃源石 | 指定次数 | 指定材料 | 结果 | +| :------: | :----: | :------: | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| | | | | 刷完现有理智即结束。 | +| 2 | | | | 先刷完现有理智,然后吃一次理智药,一共吃 `2` 次,刷完理智后结束。 | +| _999_ | 2 | | | 先刷完现有理智,并吃光理智药后,再碎石,一共碎 `2` 次,刷完理智后结束。 | +| | | 2 | | 刷 `2` 次选择的关卡即结束。 | +| | | | 2 | 掉落统计刷到 `2` 个指定的材料即结束。 | +| 2 | | 4 | | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。 | +| 2 | | | 4 | 在最多吃 `2` 次理智药的情况下,掉落统计刷到 `4` 个指定的材料即结束。 | +| 2 | | 4 | 8 | 在最多吃 `2` 次理智药的情况下,刷 `4` 次选择的关卡即结束。但如果在没刷完 `4` 次之前就获得了 `8` 个指定材料,则会提前结束。 | +| _999_ | 4 | 8 | 16 | 在最多吃光理智药并碎 `4` 次石头的情况下,刷 `8` 次选择的关卡即结束。但如果在没刷完 `8` 次之前就获得了 `16` 个指定材料,则会提前结束。 | +| | 2 | | | 先刷完现有理智,如果仓库中有理智药则结束,如果没有理智药则碎 `2` 次石,刷完理智后结束。_非 MAA GUI 行为_ | +| 2 | 4 | | | 先刷完现有理智,如果吃完 `2` 次理智药后还有理智药,则结束;如果吃完 ≤`2` 次理智药后没有理智药了,则继续碎 `4` 次石头,刷完理智后结束。_非 MAA GUI 行为_ | ::: @@ -50,7 +49,6 @@ This page is outdated and maybe still in Simplified Chinese. Translation is need - 技能书、采购凭证、碳本第 5 关,必须输入 `CA-5` / `AP-5` / `SK-5`。 - 所有芯片本。必须输入完整关卡编号,如 `PR-A-1`。 - 剿滅模式支援以下傳入值,必須使用對應的 Value: - - 當期剿滅:Annihilation - 切爾諾伯格:Chernobog@Annihilation - 龍門外環:LungmenOutskirts@Annihilation diff --git a/docs/zh-tw/manual/introduction/introduction_old.md b/docs/zh-tw/manual/introduction/introduction_old.md index 2902c8f585..1789bf84c1 100644 --- a/docs/zh-tw/manual/introduction/introduction_old.md +++ b/docs/zh-tw/manual/introduction/introduction_old.md @@ -19,7 +19,7 @@ icon: ic:baseline-article - 剿滅作戰,必須輸入 `Annihilation`。 - 部分別傳,只支援 `OF-1` / `OF-F3` / `GT-5`。 - 當期 SideStory 後三關,在自動訪問 [API](https://api.maa.plus/MaaAssistantArknights/api/gui/StageActivity.json) 下載更新後,會在主介面下方顯示相應提示。 - + ::: details 範例畫面 ![範例畫面](/images/zh-cn/combat-start-interface-example.png) @@ -32,12 +32,12 @@ icon: ic:baseline-article - `指定次數` 指定刷多少次圖(例如 “刷 15 次後停止” ) - `指定材料` 指定刷多少個指定的材料(例如 “獲取 5 個固源岩後停止” ) -| 例 | 吃理智藥 | 吃石頭 | 指定次數 | 指定材料 | 結果 | -|:---:|:-------:|:-------:|:-------:|:-------:|---------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | 999 | 10 | 1 | x | 會嘗試吃理智藥或石頭,直到刷滿 **一次**,滿足了 `指定次數:1` 的條件,即視為任務完成,停止刷理智;如果一開始理智藥不夠、石頭不夠、現有的理智也不夠就會不刷圖自動結束。| -| B | x | x | 100 | x | 會嘗試刷滿 100 次,但在目前可用理智全部刷完後(可能只刷了幾次),由於滿足了 `不吃理智藥` 、 `不吃石頭` 的條件,無理智可用,視為任務完成,停止刷理智。 | -| C | 1 | x | 100 | x | 會嘗試刷滿 100 次,期間最多吃 1 次理智藥,如果吃了一次理智藥理智也刷完了,由於滿足了 `吃理智藥:1` 、 `不吃石頭` 的條件,無理智可用,視為任務完成,停止刷理智。 | -| D | 999 | x | 100 |3 個固源岩| 會嘗試刷滿 100 次,期間會吃 999 次理智藥,但如果在這期間累計刷出了3個固源岩,由於滿足了 `指定材料:3 個固源岩` 的條件,視為任務完成,停止刷理智。 | +| 例 | 吃理智藥 | 吃石頭 | 指定次數 | 指定材料 | 結果 | +| :-: | :------: | :----: | :------: | :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| A | 999 | 10 | 1 | x | 會嘗試吃理智藥或石頭,直到刷滿 **一次**,滿足了 `指定次數:1` 的條件,即視為任務完成,停止刷理智;如果一開始理智藥不夠、石頭不夠、現有的理智也不夠就會不刷圖自動結束。 | +| B | x | x | 100 | x | 會嘗試刷滿 100 次,但在目前可用理智全部刷完後(可能只刷了幾次),由於滿足了 `不吃理智藥` 、 `不吃石頭` 的條件,無理智可用,視為任務完成,停止刷理智。 | +| C | 1 | x | 100 | x | 會嘗試刷滿 100 次,期間最多吃 1 次理智藥,如果吃了一次理智藥理智也刷完了,由於滿足了 `吃理智藥:1` 、 `不吃石頭` 的條件,無理智可用,視為任務完成,停止刷理智。 | +| D | 999 | x | 100 | 3 個固源岩 | 會嘗試刷滿 100 次,期間會吃 999 次理智藥,但如果在這期間累計刷出了3個固源岩,由於滿足了 `指定材料:3 個固源岩` 的條件,視為任務完成,停止刷理智。 | - `指定材料` 與 `關卡選擇` 是兩個互相獨立的邏輯。 - `指定材料` 只是以材料個數作為任務完成依據,並不是說你指定了材料就會幫你導航到對應關卡。 @@ -185,36 +185,36 @@ icon: ic:baseline-article - 方式 2 : 使用系統命令查看模擬器除錯通訊埠號 若使用 adb 命令的輸出結果並不能顯示 `127.0.0.1:[port]` 形式的通訊埠資訊,可以採取下面的方式查看: - 1. 首先執行一遍 adb 可執行程式(需要啟動 adb daemon 程式),並且執行需要打開明日方舟應用的模擬器。 - 2. 然後使用系統命令查看 adb 程式的通訊埠資訊。 + 1. 首先執行一遍 adb 可執行程式(需要啟動 adb daemon 程式),並且執行需要打開明日方舟應用的模擬器。 + 2. 然後使用系統命令查看 adb 程式的通訊埠資訊。 - Windows 命令 + Windows 命令 - 可以使用 `win` + `R` 輸入 `cmd` 打開命令列,使用如下命令查看: + 可以使用 `win` + `R` 輸入 `cmd` 打開命令列,使用如下命令查看: - ```sh - for /F "tokens=1,2" %A in ('"tasklist | findstr "adb""') do ( ^ - netstat -ano | findstr "%B" |) - ``` + ```sh + for /F "tokens=1,2" %A in ('"tasklist | findstr "adb""') do ( ^ + netstat -ano | findstr "%B" |) + ``` - Mac / Linux 命令 + Mac / Linux 命令 - 啟動模擬器後在終端機中輸入: + 啟動模擬器後在終端機中輸入: - ```sh - tmp=$(sudo ps aux | grep "[a]db" | awk '{print $2}') && \ - sudo netstat -vanp tcp | grep -e "\b$tmp" - ``` + ```sh + tmp=$(sudo ps aux | grep "[a]db" | awk '{print $2}') && \ + sudo netstat -vanp tcp | grep -e "\b$tmp" + ``` - 將會輸出如下形式結果,其中 `[PID]` 為 adb 實際執行的進程號,`[ADBPORT]` 為目標模擬器 adb 的遠端連接通訊埠,`[localport]` 為程式本地地址,無需關心(Mac 執行結果中也會有其他無需關心的指標): + 將會輸出如下形式結果,其中 `[PID]` 為 adb 實際執行的進程號,`[ADBPORT]` 為目標模擬器 adb 的遠端連接通訊埠,`[localport]` 為程式本地地址,無需關心(Mac 執行結果中也會有其他無需關心的指標): - ```sh - > ( netstat -ano | findstr "[PID]" ) - TCP 127.0.0.1:[localport] 127.0.0.1:0.0.0.0 LISTENING [PID] - TCP 127.0.0.1:[localport] 127.0.0.1:[ADBPORT] ESTABLISHED [PID] - # ... - # maybe more output like the above line - ``` + ```sh + > ( netstat -ano | findstr "[PID]" ) + TCP 127.0.0.1:[localport] 127.0.0.1:0.0.0.0 LISTENING [PID] + TCP 127.0.0.1:[localport] 127.0.0.1:[ADBPORT] ESTABLISHED [PID] + # ... + # maybe more output like the above line + ``` 使用結果中 `127.0.0.1:[ADBPORT]` (替換 `[ADBPORT]` 為實際數字)作為模擬器 adb 實際連接地址填入 `設定` - `連接設定` - `連接地址`。 @@ -222,9 +222,7 @@ icon: ic:baseline-article - 若需要多開模擬器同時操作,可將 MAA 資料夾複製多份,使用 **不同的 MAA**、**同一個 adb.exe**、**不同的連接地址** 來進行連接。 - **以[藍疊國際版](../../manual/device/windows.md##✅-完美支援)為例**,介紹兩種啟動多開模擬器的方式。 - - 通過為 `HD-Player.exe` 附加命令來進行多開操作。 - 1. 單獨啟動對應的模擬器 2. 打開工作管理員,找到對應模擬器程式,切換到詳細資料頁籤,在標題列點擊右鍵,選擇 `選取欄位`,把 `命令列` 勾選起來。 3. 在新出現的 `命令列` 欄位找到 `...\Bluestacks_nxt\HD-Player.exe"` 後的內容。 @@ -233,7 +231,7 @@ icon: ic:baseline-article 註:操作結束後,建議重新隱藏 `步驟 2` 中打開的 `命令列` 列以防止卡頓。 - 例子: - ``` bash + ```bash 多開1: 模擬器路徑: C:\Program Files\BlueStacks_nxt\HD-Player.exe 附加命令: --instance Nougat32 --cmd launchApp --package "com.hypergryph.arknights" @@ -245,14 +243,13 @@ icon: ic:baseline-article 其中 `--cmd launchApp --package` 部分為啟動後自動執行指定檔案名稱應用,可自行更改。 - 通過使用模擬器或應用的快捷方式來進行多開操作。 - 1. 打開多開管理器,新增對應模擬器的快捷方式。 2. 將模擬器快捷方式的路徑填入 `啟動設定` - `模擬器路徑` 中。 註:部分模擬器支援建立應用快捷方式,可直接使用應用的快捷方式直接啟動模擬器並打開明日方舟。 - 例子: - ``` bash + ```bash 多開1: 模擬器路徑: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\BlueStacks\多開1.lnk 多開2: diff --git a/docs/zh-tw/manual/newbie.md b/docs/zh-tw/manual/newbie.md index b09444e7d8..7fe5788d02 100644 --- a/docs/zh-tw/manual/newbie.md +++ b/docs/zh-tw/manual/newbie.md @@ -11,31 +11,31 @@ icon: ri:guide-fill 1. 確認系統版本 - MAA 僅支援 Windows 10 / 11,舊版 Windows 請參考[常見問題](./faq.md#系統問題)。 + MAA 僅支援 Windows 10 / 11,舊版 Windows 請參考[常見問題](./faq.md#系統問題)。 - 非 Windows 用戶請參閱[模擬器及設備支援](./device/)。 + 非 Windows 用戶請參閱[模擬器及設備支援](./device/)。 2. 下載正確的版本 - [MAA 官網](https://maa.plus/)一般會自動選擇正確的版本架構,對於大多數閱讀本文的用戶來說,應為 Windows x64。 + [MAA 官網](https://maa.plus/)一般會自動選擇正確的版本架構,對於大多數閱讀本文的用戶來說,應為 Windows x64。 3. 正確解壓 - 確認解壓完整,並確保將 MAA 解壓到一個獨立的文件夾中。請勿將 MAA 解壓到如 `C:\`、`C:\Program Files\` 等需要 UAC 權限的路徑。 + 確認解壓完整,並確保將 MAA 解壓到一個獨立的文件夾中。請勿將 MAA 解壓到如 `C:\`、`C:\Program Files\` 等需要 UAC 權限的路徑。 4. 安裝運行庫 - MAA 需要 VCRedist x64 和 .NET 8,請運行 MAA 目錄下的 `DependencySetup_依赖库安装.bat` 來安裝。 + MAA 需要 VCRedist x64 和 .NET 8,請運行 MAA 目錄下的 `DependencySetup_依赖库安装.bat` 來安裝。 - 更多信息參考[常見問題](faq.md#可能性-2--執行庫問題)。 + 更多信息參考[常見問題](faq.md#可能性-2--執行庫問題)。 5. 確認模擬器支援 - 查閱[模擬器和設備支援](./device/),確認正在使用的模擬器支援情況。 + 查閱[模擬器和設備支援](./device/),確認正在使用的模擬器支援情況。 6. 正確設置模擬器解析度 - 模擬器解析度應為橫屏的 `1280x720` 或 `1920x1080`;對於美服(YosterEN)玩家,必須為 `1920x1080`。 + 模擬器解析度應為橫屏的 `1280x720` 或 `1920x1080`;對於美服(YosterEN)玩家,必須為 `1920x1080`。 ## 初始配置 diff --git a/docs/zh-tw/protocol/callback-schema.md b/docs/zh-tw/protocol/callback-schema.md index fee09b5a96..f1bb214ed1 100644 --- a/docs/zh-tw/protocol/callback-schema.md +++ b/docs/zh-tw/protocol/callback-schema.md @@ -2,6 +2,7 @@ order: 2 icon: material-symbols:u-turn-left --- + # 回呼訊息協議 ::: info 注意 @@ -17,41 +18,41 @@ typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom ## 參數總覽 - `int msg` - 消息類型 + 消息類型 - ```cpp - enum class AsstMsg - { - /* Global Info */ - InternalError = 0, // 內部錯誤 - InitFailed = 1, // 初始化失敗 - ConnectionInfo = 2, // 連接相關資訊 - AllTasksCompleted = 3, // 全部任務完成 - AsyncCallInfo = 4, // 外部異步調用資訊 + ```cpp + enum class AsstMsg + { + /* Global Info */ + InternalError = 0, // 內部錯誤 + InitFailed = 1, // 初始化失敗 + ConnectionInfo = 2, // 連接相關資訊 + AllTasksCompleted = 3, // 全部任務完成 + AsyncCallInfo = 4, // 外部異步調用資訊 - /* TaskChain Info */ - TaskChainError = 10000, // 任務鏈執行/辨識錯誤 - TaskChainStart = 10001, // 任務鏈開始 - TaskChainCompleted = 10002, // 任務鏈完成 - TaskChainExtraInfo = 10003, // 任務鏈額外資訊 - TaskChainStopped = 10004, // 任務鏈手動停止 + /* TaskChain Info */ + TaskChainError = 10000, // 任務鏈執行/辨識錯誤 + TaskChainStart = 10001, // 任務鏈開始 + TaskChainCompleted = 10002, // 任務鏈完成 + TaskChainExtraInfo = 10003, // 任務鏈額外資訊 + TaskChainStopped = 10004, // 任務鏈手動停止 - /* SubTask Info */ - SubTaskError = 20000, // 原子任務執行/辨識錯誤 - SubTaskStart = 20001, // 原子任務開始 - SubTaskCompleted = 20002, // 原子任務完成 - SubTaskExtraInfo = 20003, // 原子任務額外資訊 - SubTaskStopped = 20004, // 原子任務手動停止 + /* SubTask Info */ + SubTaskError = 20000, // 原子任務執行/辨識錯誤 + SubTaskStart = 20001, // 原子任務開始 + SubTaskCompleted = 20002, // 原子任務完成 + SubTaskExtraInfo = 20003, // 原子任務額外資訊 + SubTaskStopped = 20004, // 原子任務手動停止 - /* Web Request */ - ReportRequest = 30000, // 上報請求 - }; - ``` + /* Web Request */ + ReportRequest = 30000, // 上報請求 + }; + ``` - `const char* details` - 消息詳情,json 字符串,詳見 [欄位解釋](#欄位解釋) + 消息詳情,json 字符串,詳見 [欄位解釋](#欄位解釋) - `void* custom_arg` - 調用方自定義參數,會原樣傳出 `AsstCreateEx` 接口中的 `custom_arg` 參數,C 系語言可利用該參數傳出 `this` 指針 + 調用方自定義參數,會原樣傳出 `AsstCreateEx` 接口中的 `custom_arg` 參數,C 系語言可利用該參數傳出 `this` 指針 ## 欄位解釋 @@ -87,25 +88,25 @@ Todo ### 常見 `What` 欄位 - `ConnectFailed` - 連接失敗 + 連接失敗 - `Connected` - 已連接,注意此時的 `uuid` 欄位值為空(下一步才是獲取) + 已連接,注意此時的 `uuid` 欄位值為空(下一步才是獲取) - `UuidGot` - 已獲取到設備唯一碼 + 已獲取到設備唯一碼 - `UnsupportedResolution` - 解析度不被支援 + 解析度不被支援 - `ResolutionError` - 解析度獲取錯誤 + 解析度獲取錯誤 - `Reconnecting` - 連接斷開(adb / 模擬器 炸了),正在重連 + 連接斷開(adb / 模擬器 炸了),正在重連 - `Reconnected` - 連接斷開(adb / 模擬器 炸了),重連成功 + 連接斷開(adb / 模擬器 炸了),重連成功 - `Disconnect` - 連接斷開(adb / 模擬器 炸了),並重試失敗 + 連接斷開(adb / 模擬器 炸了),並重試失敗 - `ScreencapFailed` - 截圖失敗(adb / 模擬器 炸了),並重試失敗 + 截圖失敗(adb / 模擬器 炸了),並重試失敗 - `TouchModeNotAvailable` - 不支援的觸控模式 + 不支援的觸控模式 ### AsyncCallInfo @@ -137,39 +138,39 @@ Todo #### 常見 `taskchain` 欄位 - `StartUp` - 開始喚醒 + 開始喚醒 - `CloseDown` - 關閉遊戲 + 關閉遊戲 - `Fight` - 刷理智 + 刷理智 - `Mall` - 信用點及購物 + 信用點及購物 - `Recruit` - 自動公招 + 自動公招 - `Infrast` - 基建換班 + 基建換班 - `Award` - 領取日常獎勵 + 領取日常獎勵 - `Roguelike` - 無限刷肉鴿 + 無限刷肉鴿 - `Copilot` - 自動抄作業 + 自動抄作業 - `SSSCopilot` - 自動抄保全作業 + 自動抄保全作業 - `Depot` - 倉庫辨識 + 倉庫辨識 - `OperBox` - 幹員 box 辨識 + 幹員 box 辨識 - `Reclamation` - 生息演算 + 生息演算 - `Custom` - 自定義任務 + 自定義任務 - `SingleStep` - 單步任務 + 單步任務 - `VideoRecognition` - 影片辨識任務 + 影片辨識任務 - `Debug` - 偵錯 + 偵錯 ### TaskChain 相關消息 @@ -200,69 +201,69 @@ Todo #### 常見 `subtask` 欄位 -- `ProcessTask` +- `ProcessTask` - ```json - // 對應的 details 欄位舉例 - { - "task": "StartButton2", // 任務名 - "action": 512, - "exec_times": 1, // 已執行次數 - "max_times": 999, // 最大執行次數 - "algorithm": 0 - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "task": "StartButton2", // 任務名 + "action": 512, + "exec_times": 1, // 已執行次數 + "max_times": 999, // 最大執行次數 + "algorithm": 0 + } + ``` - Todo 其他 ##### 常見 `task` 欄位 - `StartButton2` - 開始戰鬥 + 開始戰鬥 - `MedicineConfirm` - 使用理智藥 + 使用理智藥 - `ExpiringMedicineConfirm` - 使用 48 小時內過期的理智藥 + 使用 48 小時內過期的理智藥 - `StoneConfirm` - 碎石 + 碎石 - `RecruitRefreshConfirm` - 公招刷新標籤 + 公招刷新標籤 - `RecruitConfirm` - 公招確認招募 + 公招確認招募 - `RecruitNowConfirm` - 公招使用加急許可 + 公招使用加急許可 - `ReportToPenguinStats` - 匯報到企鵝數據統計 + 匯報到企鵝數據統計 - `ReportToYituliu` - 匯報到一圖流大數據 + 匯報到一圖流大數據 - `InfrastDormDoubleConfirmButton` - 基建宿舍的二次確認按鈕,僅當幹員衝突時才會有,請提示用戶 + 基建宿舍的二次確認按鈕,僅當幹員衝突時才會有,請提示用戶 - `StartExplore` - 肉鴿開始探索 + 肉鴿開始探索 - `StageTraderInvestConfirm` - 肉鴿投資了源石錠 + 肉鴿投資了源石錠 - `StageTraderInvestSystemFull` - 肉鴿投資達到了遊戲上限 + 肉鴿投資達到了遊戲上限 - `ExitThenAbandon` - 肉鴿放棄了本次探索 + 肉鴿放棄了本次探索 - `MissionCompletedFlag` - 肉鴿戰鬥完成 + 肉鴿戰鬥完成 - `MissionFailedFlag` - 肉鴿戰鬥失敗 + 肉鴿戰鬥失敗 - `StageTraderEnter` - 肉鴿關卡:詭異行商 + 肉鴿關卡:詭異行商 - `StageSafeHouseEnter` - 肉鴿關卡:安全的角落 + 肉鴿關卡:安全的角落 - `StageEncounterEnter` - 肉鴿關卡:不期而遇 / 古堡饋贈 + 肉鴿關卡:不期而遇 / 古堡饋贈 - `StageCombatDpsEnter` - 肉鴿關卡:普通作戰 + 肉鴿關卡:普通作戰 - `StageEmergencyDps` - 肉鴿關卡:緊急作戰 + 肉鴿關卡:緊急作戰 - `StageDreadfulFoe` - 肉鴿關卡:險路惡敵 + 肉鴿關卡:險路惡敵 - `StartGameTask` - 打開用戶端失敗(配置檔案與傳入 client_type 不匹配) + 打開用戶端失敗(配置檔案與傳入 client_type 不匹配) - Todo 其他 ### SubTaskExtraInfo @@ -280,346 +281,346 @@ Todo #### 常見 `what` 及 `details` 欄位 - `StageDrops` - 關卡材料掉落資訊 + 關卡材料掉落資訊 - ```json - // 對應的 details 欄位舉例 - { - "drops": [ // 本次辨識到的掉落材料 - { - "itemId": "3301", - "quantity": 2, - "itemName": "技巧概要·卷1" - }, - { - "itemId": "3302", - "quantity": 1, - "itemName": "技巧概要·卷2" - }, - { - "itemId": "3303", - "quantity": 2, - "itemName": "技巧概要·卷3" - } - ], - "stage": { // 關卡資訊 - "stageCode": "CA-5", - "stageId": "wk_fly_5" - }, - "stars": 3, // 行動結束星級 - "stats": [ // 本次執行期間總的材料掉落 - { - "itemId": "3301", - "itemName": "技巧概要·卷1", - "quantity": 4, - "addQuantity": 2 //本次新增的掉落數量 - }, - { - "itemId": "3302", - "itemName": "技巧概要·卷2", - "quantity": 3, - "addQuantity": 1 - }, - { - "itemId": "3303", - "itemName": "技巧概要·卷3", - "quantity": 4, - "addQuantity": 2 - } - ] - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "drops": [ // 本次辨識到的掉落材料 + { + "itemId": "3301", + "quantity": 2, + "itemName": "技巧概要·卷1" + }, + { + "itemId": "3302", + "quantity": 1, + "itemName": "技巧概要·卷2" + }, + { + "itemId": "3303", + "quantity": 2, + "itemName": "技巧概要·卷3" + } + ], + "stage": { // 關卡資訊 + "stageCode": "CA-5", + "stageId": "wk_fly_5" + }, + "stars": 3, // 行動結束星級 + "stats": [ // 本次執行期間總的材料掉落 + { + "itemId": "3301", + "itemName": "技巧概要·卷1", + "quantity": 4, + "addQuantity": 2 //本次新增的掉落數量 + }, + { + "itemId": "3302", + "itemName": "技巧概要·卷2", + "quantity": 3, + "addQuantity": 1 + }, + { + "itemId": "3303", + "itemName": "技巧概要·卷3", + "quantity": 4, + "addQuantity": 2 + } + ] + } + ``` - `RecruitTagsDetected` - 公招辨識到了 Tags + 公招辨識到了 Tags - ```json - // 對應的 details 欄位舉例 - { - "tags": [ - "費用回覆", - "防護", - "先鋒幹員", - "輔助幹員", - "近戰位" - ] - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "tags": [ + "費用回覆", + "防護", + "先鋒幹員", + "輔助幹員", + "近戰位" + ] + } + ``` - `RecruitSpecialTag` - 公招辨識到了特殊 Tag + 公招辨識到了特殊 Tag - ```json - // 對應的 details 欄位舉例 - { - "tag": "高級資深幹員" - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "tag": "高級資深幹員" + } + ``` - `RecruitResult` - 公招辨識結果 + 公招辨識結果 - ```json - // 對應的 details 欄位舉例 - { - "tags": [ // 所有辨識到的 tags,目前來說一定是 5 個 - "削弱", - "減速", - "術師幹員", - "輔助幹員", - "近戰位" - ], - "level": 4, // 總的星級 - "result": [ - { - "tags": [ - "削弱" - ], - "level": 4, // 這組 tags 的星級 - "opers": [ - { - "name": "初雪", - "level": 5 // 幹員星級 - }, - { - "name": "隕星", - "level": 5 - }, - { - "name": "槐琥", - "level": 5 - }, - { - "name": "夜煙", - "level": 4 - }, - { - "name": "流星", - "level": 4 - } - ] - }, - { - "tags": [ - "減速", - "術師幹員" - ], - "level": 4, - "opers": [ - { - "name": "夜魔", - "level": 5 - }, - { - "name": "格雷伊", - "level": 4 - } - ] - }, - { - "tags": [ - "削弱", - "術師幹員" - ], - "level": 4, - "opers": [ - { - "name": "夜煙", - "level": 4 - } - ] - } - ] - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "tags": [ // 所有辨識到的 tags,目前來說一定是 5 個 + "削弱", + "減速", + "術師幹員", + "輔助幹員", + "近戰位" + ], + "level": 4, // 總的星級 + "result": [ + { + "tags": [ + "削弱" + ], + "level": 4, // 這組 tags 的星級 + "opers": [ + { + "name": "初雪", + "level": 5 // 幹員星級 + }, + { + "name": "隕星", + "level": 5 + }, + { + "name": "槐琥", + "level": 5 + }, + { + "name": "夜煙", + "level": 4 + }, + { + "name": "流星", + "level": 4 + } + ] + }, + { + "tags": [ + "減速", + "術師幹員" + ], + "level": 4, + "opers": [ + { + "name": "夜魔", + "level": 5 + }, + { + "name": "格雷伊", + "level": 4 + } + ] + }, + { + "tags": [ + "削弱", + "術師幹員" + ], + "level": 4, + "opers": [ + { + "name": "夜煙", + "level": 4 + } + ] + } + ] + } + ``` - `RecruitTagsRefreshed` - 公招刷新了 Tags + 公招刷新了 Tags - ```json - // 對應的 details 欄位舉例 - { - "count": 1, // 當前槽位已刷新次數 - "refresh_limit": 3 // 當前槽位刷新次數上限 - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "count": 1, // 當前槽位已刷新次數 + "refresh_limit": 3 // 當前槽位刷新次數上限 + } + ``` - `RecruitNoPermit` - 公招無招聘許可 + 公招無招聘許可 - ```json - // 對應的 details 欄位舉例 - { - "continue": true, // 是否繼續刷新 - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "continue": true, // 是否繼續刷新 + } + ``` - `RecruitTagsSelected` - 公招選擇了 Tags + 公招選擇了 Tags - ```json - // 對應的 details 欄位舉例 - { - "tags": [ - "減速", - "術師幹員" - ] - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "tags": [ + "減速", + "術師幹員" + ] + } + ``` - `RecruitSlotCompleted` - 當前公招槽位任務完成 + 當前公招槽位任務完成 - `RecruitError` - 公招辨識錯誤 + 公招辨識錯誤 - `EnterFacility` - 基建進入了設施 + 基建進入了設施 - ```json - // 對應的 details 欄位舉例 - { - "facility": "Mfg", // 設施名 - "index": 0 // 設施序號 - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "facility": "Mfg", // 設施名 + "index": 0 // 設施序號 + } + ``` - `NotEnoughStaff` - 基建可用幹員不足 + 基建可用幹員不足 - ```json - // 對應的 details 欄位舉例 - { - "facility": "Mfg", // 設施名 - "index": 0 // 設施序號 - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "facility": "Mfg", // 設施名 + "index": 0 // 設施序號 + } + ``` - `ProductOfFacility` - 基建產物 + 基建產物 - ```json - // 對應的 details 欄位舉例 - { - "product": "Money", // 產物名 - "facility": "Mfg", // 設施名 - "index": 0 // 設施序號 - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "product": "Money", // 產物名 + "facility": "Mfg", // 設施名 + "index": 0 // 設施序號 + } + ``` - `StageInfo` - 自動作戰關卡資訊 + 自動作戰關卡資訊 - ```json - // 對應的 details 欄位舉例 - { - "name": string // 關卡名 - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "name": string // 關卡名 + } + ``` - `StageInfoError` - 自動作戰關卡辨識錯誤 + 自動作戰關卡辨識錯誤 - `PenguinId` - 企鵝物流 ID + 企鵝物流 ID - ```json - // 對應的 details 欄位舉例 - { - "id": string - } - ``` + ```json + // 對應的 details 欄位舉例 + { + "id": string + } + ``` - `Depot` - 倉庫辨識結果 + 倉庫辨識結果 - ```json - // 對應的 details 欄位舉例 - "done": bool, // 是否已經辨識完了,為 false 表示仍在辨識中(過程中的數據) - "arkplanner": { // https://penguin-stats.io/planner - "object": { - "items": [ - { - "id": "2004", - "have": 4, - "name": "高級作戰記錄" - }, - { - "id": "mod_unlock_token", - "have": 25, - "name": "模組數據塊" - }, - { - "id": "2003", - "have": 20, - "name": "中級作戰記錄" - } - ], - "@type": "@penguin-statistics/depot" - }, - "data": "{\"@type\":\"@penguin-statistics/depot\",\"items\":[{\"id\":\"2004\",\"have\":4,\"name\":\"高級作戰記錄\"},{\"id\":\"mod_unlock_token\",\"have\":25,\"name\":\"模組數據塊\"},{\"id\":\"2003\",\"have\":20,\"name\":\"中級作戰記錄\"}]}" - }, - "lolicon": { // https://arkntools.app/#/material - "object": { - "2004" : 4, - "mod_unlock_token": 25, - "2003": 20 - }, - "data": "{\"2003\":20,\"2004\": 4,\"mod_unlock_token\": 25}" - } - // 目前只支援 ArkPlanner 和 Lolicon (Arkntools) 的格式,以後可能會兼容更多網站 - ``` + ```json + // 對應的 details 欄位舉例 + "done": bool, // 是否已經辨識完了,為 false 表示仍在辨識中(過程中的數據) + "arkplanner": { // https://penguin-stats.io/planner + "object": { + "items": [ + { + "id": "2004", + "have": 4, + "name": "高級作戰記錄" + }, + { + "id": "mod_unlock_token", + "have": 25, + "name": "模組數據塊" + }, + { + "id": "2003", + "have": 20, + "name": "中級作戰記錄" + } + ], + "@type": "@penguin-statistics/depot" + }, + "data": "{\"@type\":\"@penguin-statistics/depot\",\"items\":[{\"id\":\"2004\",\"have\":4,\"name\":\"高級作戰記錄\"},{\"id\":\"mod_unlock_token\",\"have\":25,\"name\":\"模組數據塊\"},{\"id\":\"2003\",\"have\":20,\"name\":\"中級作戰記錄\"}]}" + }, + "lolicon": { // https://arkntools.app/#/material + "object": { + "2004" : 4, + "mod_unlock_token": 25, + "2003": 20 + }, + "data": "{\"2003\":20,\"2004\": 4,\"mod_unlock_token\": 25}" + } + // 目前只支援 ArkPlanner 和 Lolicon (Arkntools) 的格式,以後可能會兼容更多網站 + ``` - `OperBox` - 幹員辨識結果 + 幹員辨識結果 - ```json - // 對應的 details 欄位舉例 - "done": bool, // 是否已經辨識完了,為 false 表示仍在辨識中(過程中的數據) - "all_oper": [ - { - "id": "char_002_amiya", - "name": "阿米婭", - "own": true, - "rarity": 5 - }, - { - "id": "char_003_kalts", - "name": "凱爾希", - "own": true, - "rarity": 6 - }, - { - "id": "char_1020_reed2", - "name": "焰影葦草", - "own": false, - "rarity": 6 - }, - ] - "own_opers": [ - { - "id": "char_002_amiya", // 幹員id - "name": "阿米婭", // 幹員名稱 - "own": true, // 是否擁有 - "elite": 2, // 精英度 0,1,2 - "level": 50, // 幹員等級 - "potential": 6, // 幹員潛能 [1, 6] - "rarity": 5 // 幹員稀有度 [1, 6] - }, - { - "id": "char_003_kalts", - "name": "凱爾希", - "own": true, - "elite": 2, - "level": 50, - "potential": 1, - "rarity": 6 - } - ] - ``` + ```json + // 對應的 details 欄位舉例 + "done": bool, // 是否已經辨識完了,為 false 表示仍在辨識中(過程中的數據) + "all_oper": [ + { + "id": "char_002_amiya", + "name": "阿米婭", + "own": true, + "rarity": 5 + }, + { + "id": "char_003_kalts", + "name": "凱爾希", + "own": true, + "rarity": 6 + }, + { + "id": "char_1020_reed2", + "name": "焰影葦草", + "own": false, + "rarity": 6 + }, + ] + "own_opers": [ + { + "id": "char_002_amiya", // 幹員id + "name": "阿米婭", // 幹員名稱 + "own": true, // 是否擁有 + "elite": 2, // 精英度 0,1,2 + "level": 50, // 幹員等級 + "potential": 6, // 幹員潛能 [1, 6] + "rarity": 5 // 幹員稀有度 [1, 6] + }, + { + "id": "char_003_kalts", + "name": "凱爾希", + "own": true, + "elite": 2, + "level": 50, + "potential": 1, + "rarity": 6 + } + ] + ``` - `UnsupportedLevel` - 自動抄作業,不支援的關卡名 + 自動抄作業,不支援的關卡名 ### ReportRequest diff --git a/docs/zh-tw/protocol/copilot-schema.md b/docs/zh-tw/protocol/copilot-schema.md index 0af9a614a2..391bbc8538 100644 --- a/docs/zh-tw/protocol/copilot-schema.md +++ b/docs/zh-tw/protocol/copilot-schema.md @@ -2,6 +2,7 @@ order: 3 icon: ph:sword-bold --- + # 戰鬥流程協議 `resource/copilot/*.json` 的使用方法及各欄位說明 @@ -117,7 +118,7 @@ icon: ph:sword-bold // "timeout": 999999999, // 保留欄位,暫未實現。 // 超時時間。當 type 為 "部署" | "技能" 時可選。預設 INT_MAX,單位毫秒 // 等待超時則放棄當前動作, 轉而執行下一個動作 - "distance": [ 4.5, 0 ] // type 為 "移動鏡頭" 時必選 + "distance": [ 4.5, 0 ], // type 為 "移動鏡頭" 時必選 // [ x 移動格子數,y 移動格子數 ],可為小數 // 注意 "移動鏡頭" 時是辨識不到正在站場中的,需要用 sleep 完整覆蓋整個移動動畫 diff --git a/docs/zh-tw/protocol/integrated-strategy-schema.md b/docs/zh-tw/protocol/integrated-strategy-schema.md index b2ea04b149..3bff01aa36 100644 --- a/docs/zh-tw/protocol/integrated-strategy-schema.md +++ b/docs/zh-tw/protocol/integrated-strategy-schema.md @@ -2,6 +2,7 @@ order: 5 icon: ri:game-fill --- + # 集成戰略協議 ::: tip @@ -38,17 +39,17 @@ icon: ri:game-fill ### 幹員分類 -按照你的遊戲理解將幹員分成不同的 ***groups*** (群組,相關概念參考 [戰鬥流程協議](../protocol/copilot-schema.md) +按照你的遊戲理解將幹員分成不同的 **_groups_** (群組,相關概念參考 [戰鬥流程協議](../protocol/copilot-schema.md) ::: info 注意 - 1. 同一 group 內的幹員和召喚物必須部署方式一致(即同為近戰或者同為高台) +1. 同一 group 內的幹員和召喚物必須部署方式一致(即同為近戰或者同為高台) - 2. 允許同一幹員或者召喚物根據用法不同,被分類至不同的 group +2. 允許同一幹員或者召喚物根據用法不同,被分類至不同的 group - 3. 請不要修改已經存在的 group 名稱,以免在 MAA 更新時導致之前版本的作業無法使用 +3. 請不要修改已經存在的 group 名稱,以免在 MAA 更新時導致之前版本的作業無法使用 - 4. 請盡量不要新增 group,盡量將新增進作業的單位按照用法納入已經存在的 group +4. 請盡量不要新增 group,盡量將新增進作業的單位按照用法納入已經存在的 group ::: @@ -79,33 +80,33 @@ icon: ri:game-fill 1. 已有群組介紹 - 以傀影肉鴿的作業為例:主要將幹員分為了 + 以傀影肉鴿的作業為例:主要將幹員分為了 - | 分組 | 主要考量 | 主要包括職業 | 舉例幹員 | - | :--- | :--- | :--- | :--- | - | ***地面阻擋*** | 站場和清雜 | 重裝、近衛 | 奶盾、基石、羽毛筆、山、M3、令和稀音的召喚物、斑點、重裝預備幹員 | - | ***地面單切*** | 單獨對戰精英怪 | 處決者特種 | 史爾特爾、異德、麒麟R夜刀、M3、紅 | - | ***高台C*** | 常態和決戰輸出 | 狙擊、術士 | 假日威龍陳、澄閃、艾雅法拉、肥鴨 | - | ***高台輸出*** | 對空和常態輸出 | 狙擊、術士 | 空弦、能天使、克洛絲、史都華德 | - | ***奶*** | 治療能力 | 治療、輔助 | 凱爾希、濁心斯卡蒂、芙蓉、安賽爾 | - | ***回費*** | 回復 cost | 先鋒 | 桃金娘、伊內絲、芬、香草 | - | ***炮灰*** | 吸收炮彈、再部署 | 特種、召喚物 | M3、紅、桃金娘、預備幹員 | - | ***高台預備*** | 有一定輸出能力 | | 梓蘭、預備幹員 | + | 分組 | 主要考量 | 主要包括職業 | 舉例幹員 | + | :------------- | :--------------- | :----------- | :--------------------------------------------------------------- | + | **_地面阻擋_** | 站場和清雜 | 重裝、近衛 | 奶盾、基石、羽毛筆、山、M3、令和稀音的召喚物、斑點、重裝預備幹員 | + | **_地面單切_** | 單獨對戰精英怪 | 處決者特種 | 史爾特爾、異德、麒麟R夜刀、M3、紅 | + | **_高台C_** | 常態和決戰輸出 | 狙擊、術士 | 假日威龍陳、澄閃、艾雅法拉、肥鴨 | + | **_高台輸出_** | 對空和常態輸出 | 狙擊、術士 | 空弦、能天使、克洛絲、史都華德 | + | **_奶_** | 治療能力 | 治療、輔助 | 凱爾希、濁心斯卡蒂、芙蓉、安賽爾 | + | **_回費_** | 回復 cost | 先鋒 | 桃金娘、伊內絲、芬、香草 | + | **_炮灰_** | 吸收炮彈、再部署 | 特種、召喚物 | M3、紅、桃金娘、預備幹員 | + | **_高台預備_** | 有一定輸出能力 | | 梓蘭、預備幹員 | 2. 需要特殊操作的群組 - 除了上面那些比較籠統的分組,我們有時候需要對一些幹員或者幹員種類進行一些定制的精細化操作,比如 + 除了上面那些比較籠統的分組,我們有時候需要對一些幹員或者幹員種類進行一些定制的精細化操作,比如 - | 分組 | 包括幹員 | 主要特點 | - | :--- | :--- | :--- | - | 棘刺 | 棘刺、號角 | 地面遠程輸出,有些圖有非常適合的位置 | - | 召喚類 | 凱爾希、令、稀音 | 自帶地面阻擋,有的圖需要優先部署,召喚物可以當阻擋也可以當炮灰 | - | 情報官 | 曉歌、伊內絲 | 既可以回費、可以側面輸出,還可以單切 | - | 濁心斯卡蒂 | 濁心斯卡蒂 | 低壓時奶量尚可,但是範圍特殊,一些圖有比較適合的位置 | - | 焰葦 | 焰影葦草 | 薩米肉鴿常用開局幹員,兼具治療和輸出,一些圖有比較適合的位置 | - | 銀灰 | 銀灰、瑪恩納 | 地面大範圍決戰輸出,可以針對 boss 進行部署 | - | 史爾特爾 | 史爾特爾 | 由於精二後固定攜帶 3 技能,這時站場能力幾乎為零,需要阻擋位的部署優先度極低 | - | 骰子 | 骰子 | 水月肉鴿中的骰子需要單獨操作 | + | 分組 | 包括幹員 | 主要特點 | + | :--------- | :--------------- | :-------------------------------------------------------------------------- | + | 棘刺 | 棘刺、號角 | 地面遠程輸出,有些圖有非常適合的位置 | + | 召喚類 | 凱爾希、令、稀音 | 自帶地面阻擋,有的圖需要優先部署,召喚物可以當阻擋也可以當炮灰 | + | 情報官 | 曉歌、伊內絲 | 既可以回費、可以側面輸出,還可以單切 | + | 濁心斯卡蒂 | 濁心斯卡蒂 | 低壓時奶量尚可,但是範圍特殊,一些圖有比較適合的位置 | + | 焰葦 | 焰影葦草 | 薩米肉鴿常用開局幹員,兼具治療和輸出,一些圖有比較適合的位置 | + | 銀灰 | 銀灰、瑪恩納 | 地面大範圍決戰輸出,可以針對 boss 進行部署 | + | 史爾特爾 | 史爾特爾 | 由於精二後固定攜帶 3 技能,這時站場能力幾乎為零,需要阻擋位的部署優先度極低 | + | 骰子 | 骰子 | 水月肉鴿中的骰子需要單獨操作 | ::: tip 目前固定將未辨識到的地面幹員歸入倒數第二個編組後面,未辨識到的高台幹員歸入倒數第一個編組後面 @@ -153,52 +154,52 @@ icon: ri:game-fill 2. 群組內幹員各個欄位的意思和腳本相關的邏輯 - ```json - { - "theme": "Phantom", - "priority": [ - "name": "地面阻擋", // 群組名(這裡是地面阻擋組) - "doc": "標準線為 1 檔(清雜能力或者站場能力比山強)> 山 > 2 檔(阻擋 >2,可自回)> 斑點,站場能力小於斑點放到單切或者炮灰組", - // 帶 “doc” 欄位均為 json 內註解檔案,對程序執行沒有影響 - "opers": [ // 該包括哪些幹員,有序,代表部署優先度 - { - "name": "百煉嘉維爾", // 幹員名稱(這裡是百嘉,在組內第 1 位,表示需要部署地面阻擋組的時候,首先檢測是不是百嘉) - "skill": 3, // 使用幾技能(這裡舉例使用 3 技能) - "skill_usage": 2, // 技能使用模式,參考 3-3 戰鬥流程協議,不填或者 1 為自動放,2 為只放 x 次( x 通過 "skill_times" 欄位設定),3 暫時不支援 - "skill_times": 2, // 技能使用次數,預設為 1,在 "skill_usage" 欄位為 2 時生效 - "alternate_skill": 2, // 當沒有指定技能時使用的備選技能,一般是 6 星幹員未精二且精二後使用 3 技能時才需要指定(這裡指沒有 3 技能時使用 2 技能) - "alternate_skill_usage": 1 // 備選技能的技能使用模式(該欄位尚未實現) - "alternate_skill_times": 1 // 備選技能的技能使用次數(該欄位尚未實現) - "recruit_priority": 900, // 招募優先級,數字越大優先級越高,900 以上屬於看到必招,400 以下招募優先級比一些關鍵幹員精二優先度還低 - "promote_priority": 600, // 進階優先級,數字越大優先級越高,900 以上屬於有希望就精二,400 以下招募優先級低於招募普通三星幹員 - "is_key": true, // true 為 key(關鍵)幹員,false 或省略為非 key 幹員。在陣容完備檢測未通過時,僅招募 key 幹員與 0 希望幹員,保留希望。 - "is_start": true, // true 為開局選擇幹員,false 或省略為非開局幹員。在隊伍中沒有 start 幹員時,僅招募 start 幹員與 0 希望幹員,用戶填寫的幹員會強制為 start 幹員 - "promote_priority_when_team_full": 850, - "recruit_priority_offsets": [ // 按當前陣容調控招募優先級 - { - "groups": [ // 需要哪些組滿足條件 - "凱爾希", - "地面阻擋", - "棘刺" - ], - "is_less": false, // 條件是大於還是小於,false 或者省略是大於,true 是小於 - "threshold": 2, // 滿足條件的數量 - "offset": -300 // 滿足後對招募優先級的調整 - // (這裡表示當 凱爾希、地面阻擋、棘刺 這三個群組中有2名以上幹員時,百煉嘉維爾的招募優先級減 300) - } - ] - }, - ... - ], - "team_complete_condition": [ - ... - ] - } - ``` + ```json + { + "theme": "Phantom", + "priority": [ + "name": "地面阻擋", // 群組名(這裡是地面阻擋組) + "doc": "標準線為 1 檔(清雜能力或者站場能力比山強)> 山 > 2 檔(阻擋 >2,可自回)> 斑點,站場能力小於斑點放到單切或者炮灰組", + // 帶 “doc” 欄位均為 json 內註解檔案,對程序執行沒有影響 + "opers": [ // 該包括哪些幹員,有序,代表部署優先度 + { + "name": "百煉嘉維爾", // 幹員名稱(這裡是百嘉,在組內第 1 位,表示需要部署地面阻擋組的時候,首先檢測是不是百嘉) + "skill": 3, // 使用幾技能(這裡舉例使用 3 技能) + "skill_usage": 2, // 技能使用模式,參考 3-3 戰鬥流程協議,不填或者 1 為自動放,2 為只放 x 次( x 通過 "skill_times" 欄位設定),3 暫時不支援 + "skill_times": 2, // 技能使用次數,預設為 1,在 "skill_usage" 欄位為 2 時生效 + "alternate_skill": 2, // 當沒有指定技能時使用的備選技能,一般是 6 星幹員未精二且精二後使用 3 技能時才需要指定(這裡指沒有 3 技能時使用 2 技能) + "alternate_skill_usage": 1 // 備選技能的技能使用模式(該欄位尚未實現) + "alternate_skill_times": 1 // 備選技能的技能使用次數(該欄位尚未實現) + "recruit_priority": 900, // 招募優先級,數字越大優先級越高,900 以上屬於看到必招,400 以下招募優先級比一些關鍵幹員精二優先度還低 + "promote_priority": 600, // 進階優先級,數字越大優先級越高,900 以上屬於有希望就精二,400 以下招募優先級低於招募普通三星幹員 + "is_key": true, // true 為 key(關鍵)幹員,false 或省略為非 key 幹員。在陣容完備檢測未通過時,僅招募 key 幹員與 0 希望幹員,保留希望。 + "is_start": true, // true 為開局選擇幹員,false 或省略為非開局幹員。在隊伍中沒有 start 幹員時,僅招募 start 幹員與 0 希望幹員,用戶填寫的幹員會強制為 start 幹員 + "promote_priority_when_team_full": 850, + "recruit_priority_offsets": [ // 按當前陣容調控招募優先級 + { + "groups": [ // 需要哪些組滿足條件 + "凱爾希", + "地面阻擋", + "棘刺" + ], + "is_less": false, // 條件是大於還是小於,false 或者省略是大於,true 是小於 + "threshold": 2, // 滿足條件的數量 + "offset": -300 // 滿足後對招募優先級的調整 + // (這裡表示當 凱爾希、地面阻擋、棘刺 這三個群組中有2名以上幹員時,百煉嘉維爾的招募優先級減 300) + } + ] + }, + ... + ], + "team_complete_condition": [ + ... + ] + } + ``` 3. 按照你的理解新增群組和幹員 - 新增群組後,你可以從已有的群組中複製幹員過來,參考大佬們已有的評分,在此基礎上修改 + 新增群組後,你可以從已有的群組中複製幹員過來,參考大佬們已有的評分,在此基礎上修改 ## 肉鴿第二步--戰鬥邏輯 @@ -207,87 +208,85 @@ icon: ri:game-fill ### MAA肉鴿基本戰鬥邏輯--牛牛高血壓之源 1. 根據地圖上格子類型進行基本的戰鬥操作 + - MAA 會根據地圖上的格子是藍門還是紅門,是高台還是地面,能不能被部署來進行基本的戰鬥操作 - - MAA 會根據地圖上的格子是藍門還是紅門,是高台還是地面,能不能被部署來進行基本的戰鬥操作 + - MAA 僅根據地圖名稱或者編號決定使用哪份作業,不會判斷地圖的 **普通**、**緊急**、**路網**、**密文板使用** 等情況 - - MAA 僅根據地圖名稱或者編號決定使用哪份作業,不會判斷地圖的 **普通**、**緊急**、**路網**、**密文板使用** 等情況 - - - MAA 不會判斷 **作戰中地圖上無法確定的格子的情況**,比如 `馴獸小屋` 的祭壇位置,`從眾效應` 是從左邊還是從右邊出怪 + - MAA 不會判斷 **作戰中地圖上無法確定的格子的情況**,比如 `馴獸小屋` 的祭壇位置,`從眾效應` 是從左邊還是從右邊出怪 所以在後面,你需要盡量設計一套能夠應付一個地圖名 **所有不同情況**(上面提到的幾種情況)的戰鬥邏輯,小心被大家掛到 issue 上說這張圖操作高血壓哦(笑) 2. MAA 的基本作戰策略--堵藍門 + 1. 地面幹員會優先部署在藍門的格子上(為什麽是格子上,請往下看)或者周圍,方向朝向紅門(自動計算), - 1. 地面幹員會優先部署在藍門的格子上(為什麽是格子上,請往下看)或者周圍,方向朝向紅門(自動計算), + 2. 優先部署地面,然後部署治療幹員和高台幹員,一圈一圈的由藍門向四周部署, - 2. 優先部署地面,然後部署治療幹員和高台幹員,一圈一圈的由藍門向四周部署, - - 3. 會不停的按照上面的邏輯部署可以部署的東西(幹員和召喚物) + 3. 會不停的按照上面的邏輯部署可以部署的東西(幹員和召喚物) ### 優化基本戰鬥策略 1. 藍門替代方案 - 僅僅把幹員堆在藍門門口顯然不太聰明,有些關卡有格子是一夫當關萬夫莫開,防守在這裡顯然效率很高, + 僅僅把幹員堆在藍門門口顯然不太聰明,有些關卡有格子是一夫當關萬夫莫開,防守在這裡顯然效率很高, - 或者有些關卡有多個藍門,MAA 不知道哪個藍門對應哪個紅門,也會胡亂部署, + 或者有些關卡有多個藍門,MAA 不知道哪個藍門對應哪個紅門,也會胡亂部署, - 這個時候你需要打開[地圖 wiki](https://map.ark-nights.com/areas) 一邊對著地圖一邊在腦海裡指揮作戰了 + 這個時候你需要打開[地圖 wiki](https://map.ark-nights.com/areas) 一邊對著地圖一邊在腦海裡指揮作戰了 - 首先在 `設定` 裡將 `坐標展示` 切換為 `MAA` + 首先在 `設定` 裡將 `坐標展示` 切換為 `MAA` - 然後根據你的經驗尋找需要優先防守的點的坐標和朝向,寫入到 json 的 `"replacement_home"` 裡面 + 然後根據你的經驗尋找需要優先防守的點的坐標和朝向,寫入到 json 的 `"replacement_home"` 裡面 - ```json - { - "stage_name": "蓄水池", // 關卡名 - "replacement_home": [ // 重要防守點(藍門替代點),至少需要填寫 1 個 - { - "location": [ // 格子坐標,從地圖 wiki 獲得 - 6, - 4 - ], - "direction_Doc1": "優先朝向,但並不代表絕對是這個方向(算法自行判斷)", - "direction_Doc2": "不填預設 none,即沒有推薦方向,完全由算法自行判斷", - "direction_Doc3": "none / left / right / up / down / 無 / 上 / 下 / 左 / 右", - "direction": "left" // (這裡表示將幹員優先部署到坐標 6,4 的格子朝左) - } - ], - ``` + ```json + { + "stage_name": "蓄水池", // 關卡名 + "replacement_home": [ // 重要防守點(藍門替代點),至少需要填寫 1 個 + { + "location": [ // 格子坐標,從地圖 wiki 獲得 + 6, + 4 + ], + "direction_Doc1": "優先朝向,但並不代表絕對是這個方向(算法自行判斷)", + "direction_Doc2": "不填預設 none,即沒有推薦方向,完全由算法自行判斷", + "direction_Doc3": "none / left / right / up / down / 無 / 上 / 下 / 左 / 右", + "direction": "left" // (這裡表示將幹員優先部署到坐標 6,4 的格子朝左) + } + ], + ``` 2. 部署格子黑名單 - 有優先防守的點就有優先不部署幹員的點,比如大火球經過的位置,boss 腳底下,一些不好輸出的位置, + 有優先防守的點就有優先不部署幹員的點,比如大火球經過的位置,boss 腳底下,一些不好輸出的位置, - 這個時候我們引入了 `"blacklist_location"` 將不想讓他部署幹員的格子加到黑名單裡 + 這個時候我們引入了 `"blacklist_location"` 將不想讓他部署幹員的格子加到黑名單裡 - ::: info 注意 - 這裡加入的格子,就算在後面的部署策略裡面寫進去的話,也是無法部署的 - ::: + ::: info 注意 + 這裡加入的格子,就算在後面的部署策略裡面寫進去的話,也是無法部署的 + ::: - ```json - ... - "blacklist_location_Doc": "這裡是用法舉例,不是說蓄水池這個圖需要 ban 這兩個點", - "blacklist_location": [ // 禁止程序進行部署的位置 - [ - 0, - 0 - ], - [ - 1, - 1 - ] - ], - ``` + ```json + ... + "blacklist_location_Doc": "這裡是用法舉例,不是說蓄水池這個圖需要 ban 這兩個點", + "blacklist_location": [ // 禁止程序進行部署的位置 + [ + 0, + 0 + ], + [ + 1, + 1 + ] + ], + ``` 3. 其他地圖策略 - 比如水月肉鴿中如果藍門進怪了是不是要用骰子,緩解堆怪壓力 + 比如水月肉鴿中如果藍門進怪了是不是要用骰子,緩解堆怪壓力 - ```json - "not_use_dice_Doc": "藍門幹員撤退時是否需要用骰子,不寫預設 false", - "not_use_dice": false, - ``` + ```json + "not_use_dice_Doc": "藍門幹員撤退時是否需要用骰子,不寫預設 false", + "not_use_dice": false, + ``` ### 還是高血壓?是時候展現你真正的而技術了--定制作戰策略! @@ -299,113 +298,113 @@ icon: ri:game-fill 1. 使用各個群組部署幹員 - ```json - "deploy_plan": [ // 部署邏輯,按從上到下、從左到右的順序進行檢索,並嘗試部署找到的第一個幹員,如果沒有就跳過 - { - "groups": [ "百嘉", "基石", "地面C", "號角", "擋人先鋒" ], //這一步從這些群組中尋找幹員 - "location": [ 6, 4 ], //遍歷百嘉群組、基石群組、地面 C 群組等等群組 - "direction": "left" //將找到的第一個幹員部署到 6,4 這個坐標上並朝向左邊 - }, //沒找到就進行下一個部署操作 - { - "groups": [ "召喚" ], - "location": [ 6, 3 ], - "direction": "left" - }, - { - "groups": [ "單奶", "群奶" ], - "location": [ 6, 2 ], - "direction": "down" - } - ] + ```json + "deploy_plan": [ // 部署邏輯,按從上到下、從左到右的順序進行檢索,並嘗試部署找到的第一個幹員,如果沒有就跳過 + { + "groups": [ "百嘉", "基石", "地面C", "號角", "擋人先鋒" ], //這一步從這些群組中尋找幹員 + "location": [ 6, 4 ], //遍歷百嘉群組、基石群組、地面 C 群組等等群組 + "direction": "left" //將找到的第一個幹員部署到 6,4 這個坐標上並朝向左邊 + }, //沒找到就進行下一個部署操作 + { + "groups": [ "召喚" ], + "location": [ 6, 3 ], + "direction": "left" + }, + { + "groups": [ "單奶", "群奶" ], + "location": [ 6, 2 ], + "direction": "down" + } + ] - ``` + ``` 2. 在某個時間點部署幹員 ::: tip 適用於某些單切幹員或者需要炮灰的使用場景 ::: - ```json - "deploy_plan": [ - { - "groups": [ "異德", "刺客", "擋人先鋒", "其他地面" ], - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 0, 3 ] // 該操作僅在擊殺數為 0-3 時進行 - }, - { - "groups": [ "異德", "刺客", "擋人先鋒", "其他地面" ], - "location": [ 5, 3 ], - "direction": "left", - "condition": [ 6, 10 ] - }, - ... - ] - ``` + ```json + "deploy_plan": [ + { + "groups": [ "異德", "刺客", "擋人先鋒", "其他地面" ], + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 0, 3 ] // 該操作僅在擊殺數為 0-3 時進行 + }, + { + "groups": [ "異德", "刺客", "擋人先鋒", "其他地面" ], + "location": [ 5, 3 ], + "direction": "left", + "condition": [ 6, 10 ] + }, + ... + ] + ``` 3. 在某個時間點撤退幹員 ::: tip 有時候炮灰過強站住場或者需要部署位騰挪陣容怎麽辦,撤退! ::: - ```json - "retreat_plan": [ // 在特定時間點撤退目標 - { - "location": [ 4, 1 ], - "condition": [ 7, 8 ] // 在擊殺數為 7-8 時,撤去位置 [4,1] 的幹員,沒有就跳過 - } - ] - ``` + ```json + "retreat_plan": [ // 在特定時間點撤退目標 + { + "location": [ 4, 1 ], + "condition": [ 7, 8 ] // 在擊殺數為 7-8 時,撤去位置 [4,1] 的幹員,沒有就跳過 + } + ] + ``` 4. 在某個時間點釋放技能(to do) 5. 一些其他的欄位(不推薦使用) - ```json - "role_order_Doc": "幹員類型部署順序,未寫出部分以近衛,先鋒,醫療,重裝,狙擊,術士,輔助,特種,召喚物的順序補全,輸入英文", - "role_order": [ // 不推薦使用,請配置 deploy_plan 欄位 - "warrior", - "pioneer", - "medic", - "tank", - "sniper", - "caster", - "support", - "special", - "drone" - ], - "force_air_defense_when_deploy_blocking_num_Doc": "場上有 10000 個阻擋單位時就開始強制部署總共 1 個對空單位(填不填寫均不影響正常部署邏輯),在此期間不禁止部署醫療單位(不寫預設 false)", - "force_air_defense_when_deploy_blocking_num": { // 不推薦使用,請配置 deploy_plan 欄位 - "melee_num": 10000, - "air_defense_num": 1, - "ban_medic": false - }, - "force_deploy_direction_Doc": "這些點對某些職業強制部署方向", - "force_deploy_direction": [ // 不推薦使用,請配置 deploy_plan 欄位 - { - "location": [ - 1, - 1 - ], - "role_Doc": "填入的職業適用強制方向", - "role": [ - "warrior", - "pioneer" - ], - "direction": "up" - }, - { - "location": [ - 3, - 1 - ], - "role": [ - "sniper" - ], - "direction": "left" - } - ], - ``` + ```json + "role_order_Doc": "幹員類型部署順序,未寫出部分以近衛,先鋒,醫療,重裝,狙擊,術士,輔助,特種,召喚物的順序補全,輸入英文", + "role_order": [ // 不推薦使用,請配置 deploy_plan 欄位 + "warrior", + "pioneer", + "medic", + "tank", + "sniper", + "caster", + "support", + "special", + "drone" + ], + "force_air_defense_when_deploy_blocking_num_Doc": "場上有 10000 個阻擋單位時就開始強制部署總共 1 個對空單位(填不填寫均不影響正常部署邏輯),在此期間不禁止部署醫療單位(不寫預設 false)", + "force_air_defense_when_deploy_blocking_num": { // 不推薦使用,請配置 deploy_plan 欄位 + "melee_num": 10000, + "air_defense_num": 1, + "ban_medic": false + }, + "force_deploy_direction_Doc": "這些點對某些職業強制部署方向", + "force_deploy_direction": [ // 不推薦使用,請配置 deploy_plan 欄位 + { + "location": [ + 1, + 1 + ], + "role_Doc": "填入的職業適用強制方向", + "role": [ + "warrior", + "pioneer" + ], + "direction": "up" + }, + { + "location": [ + 3, + 1 + ], + "role": [ + "sniper" + ], + "direction": "left" + } + ], + ``` ### 對某個幹員打法有特殊理解?--精細化操作特定幹員 diff --git a/docs/zh-tw/protocol/integration.md b/docs/zh-tw/protocol/integration.md index 1eb92c9d4d..4b85b0aaca 100644 --- a/docs/zh-tw/protocol/integration.md +++ b/docs/zh-tw/protocol/integration.md @@ -2,6 +2,7 @@ order: 1 icon: bxs:book --- + # 集成文件 ## 接口介紹 @@ -21,22 +22,22 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha #### 返回值 - `AsstTaskId` - 若添加成功,返回該任務 ID,可用於後續設定任務參數; - 若添加失敗,返回 0 + 若添加成功,返回該任務 ID,可用於後續設定任務參數; + 若添加失敗,返回 0 #### 參數說明 - `AsstHandle handle` - 實例句柄 + 實例句柄 - `const char* type` - 任務類型 + 任務類型 - `const char* params` - 任務參數,json string + 任務參數,json string ##### 任務類型一覽 - `StartUp` - 開始喚醒 + 開始喚醒 ```json5 // 對應的任務參數 @@ -53,7 +54,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `CloseDown` - 關閉遊戲 + 關閉遊戲 ```json5 // 對應的任務參數 @@ -65,7 +66,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `Fight` - 刷理智 + 刷理智 ```json5 // 對應的任務參數 @@ -104,7 +105,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha 另支援少部分資源關卡名請參考[集成範例](https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/tools/AutoLocalization/example/zh-tw.xaml#L219) - `Recruit` - 公開招募 + 公開招募 ```json5 // 對應的任務參數 @@ -148,7 +149,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `Infrast` - 基建換班 + 基建換班 ```json5 { @@ -180,8 +181,8 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `Mall` - 領取信用及商店購物。 - 會先有序的按 `buy_first` 購買一遍,再從左到右並避開 `blacklist` 購買第二遍,在信用溢出時則會無視黑名單,從左到右購買第三遍直到不再溢出 + 領取信用及商店購物。 + 會先有序的按 `buy_first` 購買一遍,再從左到右並避開 `blacklist` 購買第二遍,在信用溢出時則會無視黑名單,從左到右購買第三遍直到不再溢出 ```json5 // 對應的任務參數 @@ -207,7 +208,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `Award` - 領取日常獎勵 + 領取日常獎勵 ```json5 // 對應的任務參數 @@ -217,7 +218,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `Roguelike` - 無限刷肉鴿 + 無限刷肉鴿 ```json5 // 對應的任務參數 @@ -283,7 +284,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `Copilot` - 自動抄作業 + 自動抄作業 ```json5 { @@ -296,7 +297,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha 作業 JSON 請參考 [3.3-戰鬥流程協議](./copilot-schema.md) - `SSSCopilot` - 自動抄保全作業 + 自動抄保全作業 ```json5 { @@ -309,7 +310,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha 保全作業 JSON 請參考 [3.7-保全派駐協議](./sss-schema.md) - `Depot` - 倉庫辨識 + 倉庫辨識 ```json5 // 對應的任務參數 @@ -319,7 +320,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `OperBox` - 幹員 box 辨識 + 幹員 box 辨識 ```json5 // 對應的任務參數 @@ -329,7 +330,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha ``` - `Reclamation` - 生息演算 + 生息演算 ```json5 { @@ -344,7 +345,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha "tools_to_craft": [ string, // 自動製造的物品,可選項,默認為荧光棒 ... - ] + ], // 建議填寫子串 "increment_mode": int, // 點擊類型,可選項。默認為0 // 0 - 連點 @@ -353,7 +354,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha } ``` -- `Custom` +- `Custom` 自定義任務 @@ -368,7 +369,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha } ``` -- `SingleStep` +- `SingleStep` 單步任務(目前僅支援戰鬥) @@ -387,7 +388,7 @@ AsstTaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const cha } ``` -- `VideoRecognition` +- `VideoRecognition` 影片辨識,目前僅支援作業(作戰)影片 @@ -413,17 +414,17 @@ bool ASSTAPI AsstSetTaskParams(AsstHandle handle, AsstTaskId id, const char* par #### 返回值 - `bool` - 返回是否設定成功 + 返回是否設定成功 #### 參數說明 - `AsstHandle handle` - 實例句柄 + 實例句柄 - `AsstTaskId task` - 任務 ID, `AsstAppendTask` 接口的返回值 + 任務 ID, `AsstAppendTask` 接口的返回值 - `const char* params` - 任務參數,json string,與 `AsstAppendTask` 接口相同。 - 未標注 “不支援執行中設定” 的欄位都支援實時修改;否則若當前任務正在執行,會忽略對應的欄位 + 任務參數,json string,與 `AsstAppendTask` 接口相同。 + 未標注 “不支援執行中設定” 的欄位都支援實時修改;否則若當前任務正在執行,會忽略對應的欄位 ### `AsstSetStaticOption` @@ -440,14 +441,14 @@ bool ASSTAPI AsstSetStaticOption(AsstStaticOptionKey key, const char* value); #### 返回值 - `bool` - 返回是否設定成功 + 返回是否設定成功 #### 參數說明 - `AsstStaticOptionKey key` - 鍵 + 鍵 - `const char* value` - 值 + 值 ##### 鍵值一覽 @@ -468,16 +469,16 @@ bool ASSTAPI AsstSetInstanceOption(AsstHandle handle, AsstInstanceOptionKey key, #### 返回值 - `bool` - 返回是否設定成功 + 返回是否設定成功 #### 參數說明 - `AsstHandle handle` - 實例句柄 + 實例句柄 - `AsstInstanceOptionKey key` - 鍵 + 鍵 - `const char* value` - 值 + 值 ##### 鍵值一覽 diff --git a/docs/zh-tw/protocol/remote-control-schema.md b/docs/zh-tw/protocol/remote-control-schema.md index 27de9ac115..65eaea11d6 100644 --- a/docs/zh-tw/protocol/remote-control-schema.md +++ b/docs/zh-tw/protocol/remote-control-schema.md @@ -88,6 +88,7 @@ MAA 會以 1 秒的間隔持續輪詢這個端點,嘗試獲取它要執行的 - Settings-[SettingsName] 型的任務的 type 的可選值為 Settings-ConnectionAddress, Settings-Stage1 - Settings 系列任務仍然是要按順序執行的,並不會在收到任務的時候立刻執行,而是排在上一個任務的後面 - 多個立即執行的任務也會按下發順序執行,只不過這些任務的執行速度都很快,通常來說,並不需要關注他們的順序。 + ::: ## 匯報任務端點 diff --git a/docs/zh-tw/protocol/sss-schema.md b/docs/zh-tw/protocol/sss-schema.md index 03c1484b40..42f9bbe5bc 100644 --- a/docs/zh-tw/protocol/sss-schema.md +++ b/docs/zh-tw/protocol/sss-schema.md @@ -2,6 +2,7 @@ order: 7 icon: game-icons:prisoner --- + # 保全派駐協議 ::: tip diff --git a/docs/zh-tw/protocol/task-schema.md b/docs/zh-tw/protocol/task-schema.md index 2af93cde24..506a82b796 100644 --- a/docs/zh-tw/protocol/task-schema.md +++ b/docs/zh-tw/protocol/task-schema.md @@ -173,10 +173,10 @@ JSON 文件是不支持注釋的,文本中的注釋僅用於示範,請勿直 "ratio": 0.6, // KNN 匹配演算法的距離比值, [0 - 1.0], 越大則匹配越寬鬆, 更容易連線. 預設0.6 "detector": "SIFT", // 特徵點偵測器類型, 可選值為 SIFT, ORB, BRISK, KAZE, AKAZE, SURF; 預設值 = SIFT - // SIFT: 計算複雜度高,具有尺度不變性、旋轉不變性。效果最好。 - // ORB: 計算速度非常快,具有旋轉不變性。但不具有尺度不變性。 - // BRISK: 計算速度非常快,具有尺度不變性、旋轉不變性。 - // KAZE: 適用於2D和3D影像,具有尺度不變性、旋轉不變性。 + // SIFT: 計算複雜度高,具有尺度不變性、旋轉不變性。效果最好。 + // ORB: 計算速度非常快,具有旋轉不變性。但不具有尺度不變性。 + // BRISK: 計算速度非常快,具有尺度不變性、旋轉不變性。 + // KAZE: 適用於2D和3D影像,具有尺度不變性、旋轉不變性。 // AKAZE: 計算速度較快,具有尺度不變性、旋轉不變性。 } } @@ -192,23 +192,23 @@ Template task 與 base task 合稱**範本任務**。 - 如果 `tasks.json` 中未顯式定義任務 "B@A",則在 `sub`, `next`, `onErrorNext`, `exceededNext`, `reduceOtherTimes` 欄位中增加 `B@` 首碼(如遇任務名開頭為 `#` 則增加 `B` 首碼),其餘參數與 "A" 任務相同。就是說如果任務 "A" 有以下參數: - ```json - "A": { - "template": "A.png", - ..., - "next": [ "N1", "N2" ] - } - ``` + ```json + "A": { + "template": "A.png", + ..., + "next": [ "N1", "N2" ] + } + ``` - 就相當於同時定義了 + 就相當於同時定義了 - ```json - "B@A": { - "template": "A.png", - ..., - "next": [ "B@N1", "B@N2" ] - } - ``` + ```json + "B@A": { + "template": "A.png", + ..., + "next": [ "B@N1", "B@N2" ] + } + ``` - 如果 `tasks.json` 中定義了任務 "B@A",則: 1. 如果 "B@A" 與 "A" 的 `algorithm` 欄位不同,則派生類參數不繼承(只繼承 `TaskInfo` 定義的參數) @@ -238,11 +238,11 @@ Virtual task 也稱 sharp task(`#` 型任務)。 任務名帶 `#` 的任務即為 virtual task。 `#` 後可接 `next`, `back`, `self`, `sub`, `on_error_next`, `exceeded_next`, `reduce_other_times`。 -| 虛任務類型 | 含義 | 簡單範例 | -|:---------:|:---:|:--------:| -| self | 父任務名 | `"A": {"next": "#self"}` 中的 `"#self"` 被解釋為 `"A"`
`"B": {"next": "A@B@C#self"}` 中的 `"A@B@C#self"` 被解釋為 `"B"`。1 | -| back | # 前面的任務名 | `"A@B#back"` 被解釋為 `"A@B"`
`"#back"` 直接出現則會被跳過 | -| next, sub 等 | # 前任務名對應欄位 | 以 `next` 為例:
`"A#next"` 被解釋為 `Task.get("A")->next`
`"#next"` 直接出現則會被跳過 | +| 虛任務類型 | 含義 | 簡單範例 | +| :----------: | :----------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | +| self | 父任務名 | `"A": {"next": "#self"}` 中的 `"#self"` 被解釋為 `"A"`
`"B": {"next": "A@B@C#self"}` 中的 `"A@B@C#self"` 被解釋為 `"B"`。1 | +| back | # 前面的任務名 | `"A@B#back"` 被解釋為 `"A@B"`
`"#back"` 直接出現則會被跳過 | +| next, sub 等 | # 前任務名對應欄位 | 以 `next` 為例:
`"A#next"` 被解釋為 `Task.get("A")->next`
`"#next"` 直接出現則會被跳過 | _Note1: `"XXX#self"` 與 `"#self"` 含義相同。_ @@ -312,7 +312,7 @@ Task.get_raw("B@Loading")->next = { "B#self", "B#next", "B#back" }; "next": [ "zzz" ] } } - ``` +``` 以下程式碼可以實現根據 mode 的值改變任務 "A",同時會改變其它依賴任務 "A" 的任務,如 "B@A": @@ -332,14 +332,14 @@ default: ## 運算式計算 -| 符號 | 含義 | 實例 | -|:---------:|:---:|:--------:| -| `@` | 範本任務 | `Fight@ReturnTo` | -| `#`(單目) | 虛任務 | `#self` | -| `#`(雙目) | 虛任務 | `StartUpThemes#next` | -| `*` | 重複多個任務 | `(ClickCornerAfterPRTS+ClickCorner)*5` | -| `+` | 任務清單合併(在 next 系列屬性中同名任務只保留最靠前者) | `A+B` | -| `^` | 任務列表差(在前者但不在後者,順序不變)| `(A+A+B+C)^(A+B+D)`(結果為 `C`) | +| 符號 | 含義 | 實例 | +| :---------: | :------------------------------------------------------: | :------------------------------------: | +| `@` | 範本任務 | `Fight@ReturnTo` | +| `#`(單目) | 虛任務 | `#self` | +| `#`(雙目) | 虛任務 | `StartUpThemes#next` | +| `*` | 重複多個任務 | `(ClickCornerAfterPRTS+ClickCorner)*5` | +| `+` | 任務清單合併(在 next 系列屬性中同名任務只保留最靠前者) | `A+B` | +| `^` | 任務列表差(在前者但不在後者,順序不變) | `(A+A+B+C)^(A+B+D)`(結果為 `C`) | 運算子 `@`, `#`, `*`, `+`, `^` 有優先順序:`#`(單目)> `@` = `#`(雙目)> `*` > `+` = `^`。 diff --git a/docs/zh-tw/readme.md b/docs/zh-tw/readme.md index 081a2dc34a..47ccdd2b1f 100644 --- a/docs/zh-tw/readme.md +++ b/docs/zh-tw/readme.md @@ -26,7 +26,7 @@ MAA 的意思是 MAA Assistant Arknights 基於圖像辨識技術,一鍵完成全部日常任務! -絕讚更新中 ✿✿ヽ(°▽°)ノ✿ +絕讚更新中 ✿✿ヽ(°▽°)ノ✿ ::: @@ -137,9 +137,9 @@ MAA 以中文(簡體)為第一語言,翻譯詞條皆以中文(簡體) 1. 下載預構建的第三方庫 - ```cmd - python tools/maadeps-download.py - ``` + ```cmd + python tools/maadeps-download.py + ``` 2. 使用 Visual Studio 2022 打開 `MAA.sln`,右鍵 `MaaWpfGui`,設為啟動項目 3. VS 上方配置選擇 `RelWithDebInfo`, `x64` (如果編譯 Release 包 或 ARM 平台,請忽略這步) @@ -193,9 +193,9 @@ MAA 以中文(簡體)為第一語言,翻譯詞條皆以中文(簡體) Discord 伺服器:[Discord](https://discord.gg/23DfZ9uA4V) 用戶交流 TG 群:[Telegram 群](https://t.me/+Mgc2Zngr-hs3ZjU1) 自動戰鬥 JSON 作業分享:[prts.plus](https://prts.plus) 或 [抄作業.com](http://抄作業.com) -Bilibili 直播間:[MrEO 直播間](https://live.bilibili.com/2808861) 直播敲代碼 & [MAA-Official 直播間](https://live.bilibili.com/27548877) 遊戲/雜談 +Bilibili 直播間:[MrEO 直播間](https://live.bilibili.com/2808861) 直播敲代碼 & [MAA-Official 直播間](https://live.bilibili.com/27548877) 遊戲/雜談 技術群(舟無關、禁水):[內卷地獄!(QQ 群)](https://jq.qq.com/?_wv=1027&k=ypbzXcA2) -開發者群:[QQ 群](https://jq.qq.com/?_wv=1027&k=JM9oCk3C) +開發者群:[QQ 群](https://jq.qq.com/?_wv=1027&k=JM9oCk3C) 如果覺得軟體對你有幫助,幫忙點個 Star 吧!~(網頁最上方右上角的小星星),這就是對我們最大的支持了! diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..5d7bf33d94 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.isort] +profile = "black" diff --git a/src/MaaCore/re-include.py b/src/MaaCore/re-include.py index d8b62c1dea..51cf0633af 100644 --- a/src/MaaCore/re-include.py +++ b/src/MaaCore/re-include.py @@ -3,41 +3,41 @@ import os all_headers = {} for root, dirs, files in os.walk("."): - if root.startswith('.'): + if root.startswith("."): root = root[1:] - root = root.replace('\\', '/') - if root.startswith('/'): + root = root.replace("\\", "/") + if root.startswith("/"): root = root[1:] - if root and not root.endswith('/'): - root += '/' + if root and not root.endswith("/"): + root += "/" for f in files: - if f.endswith(('.h', '.hpp')): + if f.endswith((".h", ".hpp")): all_headers[f] = root print(all_headers) for root, dirs, files in os.walk("."): - if root.startswith('.'): + if root.startswith("."): root = root[1:] - root = root.replace('\\', '/') - if root.startswith('/'): + root = root.replace("\\", "/") + if root.startswith("/"): root = root[1:] - if root and not root.endswith('/'): - root += '/' + if root and not root.endswith("/"): + root += "/" for f in files: - if not f.endswith(('.h', '.hpp', '.c', '.cpp', '.cc')): + if not f.endswith((".h", ".hpp", ".c", ".cpp", ".cc")): continue - temp = '' - with open(root + f, encoding='utf-8') as fp: + temp = "" + with open(root + f, encoding="utf-8") as fp: for line in fp.readlines(): - if line.startswith('#include') and '<' not in line: - if '/' in line: - header = line[line.rindex('/') + 1: len(line) - 2] + if line.startswith("#include") and "<" not in line: + if "/" in line: + header = line[line.rindex("/") + 1 : len(line) - 2] else: - header = line[line.index('"') + 1: len(line) - 2] + header = line[line.index('"') + 1 : len(line) - 2] if header in all_headers: - new_header = all_headers[header].replace(root, '') - new_line = f"#include \"{new_header}{header}\"\n" + new_header = all_headers[header].replace(root, "") + new_line = f'#include "{new_header}{header}"\n' print(new_line) temp += new_line else: @@ -45,5 +45,5 @@ for root, dirs, files in os.walk("."): else: temp += line - with open(root + f, mode='w', encoding='utf-8') as fp: + with open(root + f, mode="w", encoding="utf-8") as fp: fp.write(temp) diff --git a/src/Python/asst/__init__.py b/src/Python/asst/__init__.py index 9bde90e41c..ba8c17986e 100644 --- a/src/Python/asst/__init__.py +++ b/src/Python/asst/__init__.py @@ -1 +1 @@ -__all__ = ['asst', 'emulator', 'updater', 'utils'] +__all__ = ["asst", "emulator", "updater", "utils"] diff --git a/src/Python/asst/asst.py b/src/Python/asst/asst.py index 29a772dc0e..b02f8c50e7 100644 --- a/src/Python/asst/asst.py +++ b/src/Python/asst/asst.py @@ -4,14 +4,15 @@ import json import os import pathlib import platform -from typing import Union, Optional +from typing import Optional, Union -from .utils import InstanceOptionType, StaticOptionType, JSON +from .utils import JSON, InstanceOptionType, StaticOptionType class Asst: CallBackType = ctypes.CFUNCTYPE( - None, ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p) + None, ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p + ) """ 回调函数,使用实例可参照 my_callback @@ -22,8 +23,11 @@ class Asst: """ @staticmethod - def load(path: Union[pathlib.Path, str], incremental_path: Optional[Union[pathlib.Path, str]] = None, - user_dir: Optional[Union[pathlib.Path, str]] = None) -> bool: + def load( + path: Union[pathlib.Path, str], + incremental_path: Optional[Union[pathlib.Path, str]] = None, + user_dir: Optional[Union[pathlib.Path, str]] = None, + ) -> bool: """ 加载 dll 及资源 @@ -34,49 +38,46 @@ class Asst: """ platform_values = { - 'windows': { - 'libpath': 'MaaCore.dll', - 'environ_var': 'PATH' + "windows": {"libpath": "MaaCore.dll", "environ_var": "PATH"}, + "darwin": { + "libpath": "libMaaCore.dylib", + "environ_var": "DYLD_LIBRARY_PATH", }, - 'darwin': { - 'libpath': 'libMaaCore.dylib', - 'environ_var': 'DYLD_LIBRARY_PATH' - }, - 'linux': { - 'libpath': 'libMaaCore.so', - 'environ_var': 'LD_LIBRARY_PATH' - } + "linux": {"libpath": "libMaaCore.so", "environ_var": "LD_LIBRARY_PATH"}, } lib_import_func = None platform_type = platform.system().lower() - if platform_type == 'windows': + if platform_type == "windows": lib_import_func = ctypes.WinDLL else: lib_import_func = ctypes.CDLL - Asst.__libpath = pathlib.Path(path) / platform_values[platform_type]['libpath'] + Asst.__libpath = pathlib.Path(path) / platform_values[platform_type]["libpath"] try: - os.environ[platform_values[platform_type]['environ_var']] += os.pathsep + str(path) + os.environ[ + platform_values[platform_type]["environ_var"] + ] += os.pathsep + str(path) except KeyError: - os.environ[platform_values[platform_type]['environ_var']] = os.pathsep + str(path) + os.environ[platform_values[platform_type]["environ_var"]] = ( + os.pathsep + str(path) + ) try: Asst.__lib = lib_import_func(str(Asst.__libpath)) except OSError: - Asst.__libpath = ctypes.util.find_library('MaaCore') + Asst.__libpath = ctypes.util.find_library("MaaCore") Asst.__lib = lib_import_func(str(Asst.__libpath)) Asst.__set_lib_properties() ret: bool = True if user_dir: - ret &= Asst.__lib.AsstSetUserDir(str(user_dir).encode('utf-8')) + ret &= Asst.__lib.AsstSetUserDir(str(user_dir).encode("utf-8")) - ret &= Asst.__lib.AsstLoadResource(str(path).encode('utf-8')) + ret &= Asst.__lib.AsstLoadResource(str(path).encode("utf-8")) if incremental_path: - ret &= Asst.__lib.AsstLoadResource( - str(incremental_path).encode('utf-8')) + ret &= Asst.__lib.AsstLoadResource(str(incremental_path).encode("utf-8")) return ret @@ -107,8 +108,9 @@ class Asst: :return: 是否设置成功 """ - return Asst.__lib.AsstSetInstanceOption(self.__ptr, - int(option_type), option_value.encode('utf-8')) + return Asst.__lib.AsstSetInstanceOption( + self.__ptr, int(option_type), option_value.encode("utf-8") + ) def set_static_option(option_type: StaticOptionType, option_value: str): """ @@ -121,9 +123,11 @@ class Asst: :return: 是否设置成功 """ - return Asst.__lib.AsstSetStaticOption(int(option_type), option_value.encode('utf-8')) + return Asst.__lib.AsstSetStaticOption( + int(option_type), option_value.encode("utf-8") + ) - def connect(self, adb_path: str, address: str, config: str = 'General'): + def connect(self, adb_path: str, address: str, config: str = "General"): """ 连接设备 @@ -134,8 +138,12 @@ class Asst: :return: 是否连接成功 """ - return Asst.__lib.AsstConnect(self.__ptr, - adb_path.encode('utf-8'), address.encode('utf-8'), config.encode('utf-8')) + return Asst.__lib.AsstConnect( + self.__ptr, + adb_path.encode("utf-8"), + address.encode("utf-8"), + config.encode("utf-8"), + ) def get_image(self, size: int) -> bytes | None: """ @@ -147,9 +155,8 @@ class Asst: """ buffer_type = ctypes.c_byte * size buffer = buffer_type() - buffer.value = b'\000' * size - if (got := Asst.__lib.AsstGetImage(self.__ptr, buffer, size)) \ - and got > 0: + buffer.value = b"\000" * size + if (got := Asst.__lib.AsstGetImage(self.__ptr, buffer, size)) and got > 0: return bytes(buffer) else: return None @@ -162,7 +169,9 @@ class Asst: ``name``: Extras名称 ``extras``: Extras配置 """ - Asst.__lib.AsstSetConnectionExtras(name.encode('utf-8'), json.dumps(extras, ensure_ascii=False).encode('utf-8')) + Asst.__lib.AsstSetConnectionExtras( + name.encode("utf-8"), json.dumps(extras, ensure_ascii=False).encode("utf-8") + ) TaskId = int @@ -176,8 +185,11 @@ class Asst: :return: 任务 ID, 可用于 set_task_params 接口 """ - return Asst.__lib.AsstAppendTask(self.__ptr, type_name.encode('utf-8'), - json.dumps(params, ensure_ascii=False).encode('utf-8')) + return Asst.__lib.AsstAppendTask( + self.__ptr, + type_name.encode("utf-8"), + json.dumps(params, ensure_ascii=False).encode("utf-8"), + ) def set_task_params(self, task_id: TaskId, params: JSON) -> bool: """ @@ -189,7 +201,9 @@ class Asst: :return: 是否成功 """ - return Asst.__lib.AsstSetTaskParams(self.__ptr, task_id, json.dumps(params, ensure_ascii=False).encode('utf-8')) + return Asst.__lib.AsstSetTaskParams( + self.__ptr, task_id, json.dumps(params, ensure_ascii=False).encode("utf-8") + ) def start(self) -> bool: """ @@ -225,7 +239,7 @@ class Asst: ``message``: 日志内容 """ - Asst.__lib.AsstLog(level.encode('utf-8'), message.encode('utf-8')) + Asst.__lib.AsstLog(level.encode("utf-8"), message.encode("utf-8")) def get_version(self) -> str: """ @@ -233,58 +247,83 @@ class Asst: : return: 版本号 """ - return Asst.__lib.AsstGetVersion().decode('utf-8') + return Asst.__lib.AsstGetVersion().decode("utf-8") @staticmethod def __set_lib_properties(): Asst.__lib.AsstSetUserDir.restype = ctypes.c_bool - Asst.__lib.AsstSetUserDir.argtypes = ( - ctypes.c_char_p,) + Asst.__lib.AsstSetUserDir.argtypes = (ctypes.c_char_p,) Asst.__lib.AsstLoadResource.restype = ctypes.c_bool - Asst.__lib.AsstLoadResource.argtypes = ( - ctypes.c_char_p,) + Asst.__lib.AsstLoadResource.argtypes = (ctypes.c_char_p,) Asst.__lib.AsstSetStaticOption.restype = ctypes.c_bool Asst.__lib.AsstSetStaticOption.argtypes = ( - ctypes.c_int, ctypes.c_char_p,) + ctypes.c_int, + ctypes.c_char_p, + ) Asst.__lib.AsstSetConnectionExtras.restype = ctypes.c_void_p Asst.__lib.AsstSetConnectionExtras.argtypes = ( - ctypes.c_char_p, ctypes.c_char_p,) + ctypes.c_char_p, + ctypes.c_char_p, + ) Asst.__lib.AsstGetImage.restype = ctypes.c_uint64 Asst.__lib.AsstGetImage.argtypes = ( - ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint64) + ctypes.c_void_p, + ctypes.c_void_p, + ctypes.c_uint64, + ) Asst.__lib.AsstCreate.restype = ctypes.c_void_p Asst.__lib.AsstCreate.argtypes = () Asst.__lib.AsstCreateEx.restype = ctypes.c_void_p Asst.__lib.AsstCreateEx.argtypes = ( - ctypes.c_void_p, ctypes.c_void_p,) + ctypes.c_void_p, + ctypes.c_void_p, + ) Asst.__lib.AsstDestroy.argtypes = (ctypes.c_void_p,) Asst.__lib.AsstSetInstanceOption.restype = ctypes.c_bool Asst.__lib.AsstSetInstanceOption.argtypes = ( - ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p,) + ctypes.c_void_p, + ctypes.c_int, + ctypes.c_char_p, + ) Asst.__lib.AsstConnect.restype = ctypes.c_bool Asst.__lib.AsstConnect.argtypes = ( - ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,) + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, + ) Asst.__lib.AsstAsyncConnect.restype = ctypes.c_int Asst.__lib.AsstAsyncConnect.argtypes = ( - ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_bool) + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_bool, + ) Asst.__lib.AsstAppendTask.restype = ctypes.c_int Asst.__lib.AsstAppendTask.argtypes = ( - ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p) + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_char_p, + ) Asst.__lib.AsstSetTaskParams.restype = ctypes.c_bool Asst.__lib.AsstSetTaskParams.argtypes = ( - ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p) + ctypes.c_void_p, + ctypes.c_int, + ctypes.c_char_p, + ) Asst.__lib.AsstStart.restype = ctypes.c_bool Asst.__lib.AsstStart.argtypes = (ctypes.c_void_p,) @@ -298,5 +337,4 @@ class Asst: Asst.__lib.AsstGetVersion.restype = ctypes.c_char_p Asst.__lib.AsstLog.restype = None - Asst.__lib.AsstLog.argtypes = ( - ctypes.c_char_p, ctypes.c_char_p) + Asst.__lib.AsstLog.argtypes = (ctypes.c_char_p, ctypes.c_char_p) diff --git a/src/Python/asst/downloader.py b/src/Python/asst/downloader.py index 3eca2faaf5..895532e72d 100644 --- a/src/Python/asst/downloader.py +++ b/src/Python/asst/downloader.py @@ -1,22 +1,24 @@ +import json import os import shutil -import json from concurrent.futures import ThreadPoolExecutor from threading import Lock + import requests + # 获取文件大小 def length(url_list): def getlenhead(single_url): response = requests.head(single_url) - while 'Location' in response.headers: - response = requests.head(response.headers.get('Location')) - file_size = response.headers.get('Content-Length') + while "Location" in response.headers: + response = requests.head(response.headers.get("Location")) + file_size = response.headers.get("Content-Length") if file_size is not None: return int(file_size) else: return False - + for url in url_list: try: single_file_length = getlenhead(url) @@ -26,6 +28,7 @@ def length(url_list): print(f"{url} 无法连接") print(e) + # 定义Download类在初始化时保存几个参数 class Downloader: # 初始化类 @@ -36,32 +39,50 @@ class Downloader: self.proxies = use_proxies # 代理服务器 self.lock = Lock() self.chunk_status = [] # 状态列表 - self.failed_requests = {url: {'success': 0, 'fail': 0} for url in urlist} # 记录每个 URL 的失败次数和成功次数 + self.failed_requests = { + url: {"success": 0, "fail": 0} for url in urlist + } # 记录每个 URL 的失败次数和成功次数 self.listhash = hex(hash(tuple(urlist))) # 计算urlist的hash def download_chunk(self, url, chunk_id, total_size): start = chunk_id * self.chunksize end = min(start + self.chunksize - 1, total_size - 1) - headers = {'Range': f'bytes={start}-{end}'} + headers = {"Range": f"bytes={start}-{end}"} filename = f"temp/{self.listhash}/{chunk_id}" if self.chunk_status[chunk_id] != 2: try: - response = requests.get(url, headers=headers, proxies=self.proxies, timeout=5) - if response.status_code in (301, 302, 303, 307, 308): # 处理HTTP 3xx 重定向问题,继续发送原来的header(range) - redirect_url = response.headers['Location'] - response = requests.get(redirect_url, headers=headers, timeout=3, proxies=self.proxies) + response = requests.get( + url, headers=headers, proxies=self.proxies, timeout=5 + ) + if response.status_code in ( + 301, + 302, + 303, + 307, + 308, + ): # 处理HTTP 3xx 重定向问题,继续发送原来的header(range) + redirect_url = response.headers["Location"] + response = requests.get( + redirect_url, headers=headers, timeout=3, proxies=self.proxies + ) if response.status_code == 206: # 206状态码 - self.failed_requests[url]['success'] += 1 - with open(filename, 'wb') as file: + self.failed_requests[url]["success"] += 1 + with open(filename, "wb") as file: file.write(response.content) self.chunk_status[chunk_id] = 2 elif response.status_code >= 400: - self.failed_requests[url]['fail'] += 1 + self.failed_requests[url]["fail"] += 1 - if self.failed_requests[url]['fail'] / ( - self.failed_requests[url]['success'] + self.failed_requests[url]['fail']) > 0.5 and \ - self.failed_requests[url]['fail'] > 10: + if ( + self.failed_requests[url]["fail"] + / ( + self.failed_requests[url]["success"] + + self.failed_requests[url]["fail"] + ) + > 0.5 + and self.failed_requests[url]["fail"] > 10 + ): # 如果某 URL 的失败率高于 50%,则跳过该 URL return except Exception as e: @@ -72,44 +93,47 @@ class Downloader: num_chunks = (total_size + self.chunksize - 1) // self.chunksize self.chunk_status = [0] * num_chunks try: - shutil.rmtree(f'temp/{self.listhash}') + shutil.rmtree(f"temp/{self.listhash}") except: pass - os.makedirs(f'temp/{self.listhash}', exist_ok=True) + os.makedirs(f"temp/{self.listhash}", exist_ok=True) max_retry = 3 while 0 in self.chunk_status: if max_retry == 0: print("下载出错。") return - with ThreadPoolExecutor(max_workers=self.max_conn * len(self.urlist)) as executor: + with ThreadPoolExecutor( + max_workers=self.max_conn * len(self.urlist) + ) as executor: for url in self.urlist: for chunk_id in range(num_chunks): executor.submit(self.download_chunk, url, chunk_id, total_size) max_retry -= 1 - # 合并所有临时文件到一个文件 - with open(file_path, 'wb') as outfile: + with open(file_path, "wb") as outfile: for chunk_id in range(num_chunks): filename = f"temp/{self.listhash}/{chunk_id}" - with open(filename, 'rb') as infile: + with open(filename, "rb") as infile: shutil.copyfileobj(infile, outfile) # 删除临时目录 - shutil.rmtree(f'temp/{self.listhash}') + shutil.rmtree(f"temp/{self.listhash}") # 验证下载文件 if os.path.getsize(file_path) != total_size: print("文件大小不一致,下载可能出错。") - + return True def file_download(download_url_list, download_path, request_proxies=None): - chunksize = 4 * 1024 * 1024 # 分片大小4MB - max_conn = 4 # 最大连接数 + chunksize = 4 * 1024 * 1024 # 分片大小4MB + max_conn = 4 # 最大连接数 # 创建对象 - downloader = Downloader(download_url_list, chunksize, max_conn, use_proxies=request_proxies) + downloader = Downloader( + download_url_list, chunksize, max_conn, use_proxies=request_proxies + ) # 下载文件 total_size = length(download_url_list) @@ -120,7 +144,7 @@ def file_download(download_url_list, download_path, request_proxies=None): return downloader.download_file(total_size, download_path) -if __name__ == '__main__': +if __name__ == "__main__": while True: json_string = input("请输入下载指令:") # 解析JSON字符串 @@ -142,7 +166,9 @@ if __name__ == '__main__': proxies = data.get("proxies", None) # 对于变量的类型进行检查 - if not isinstance(urlist, list) or not all(isinstance(url, str) for url in urlist): + if not isinstance(urlist, list) or not all( + isinstance(url, str) for url in urlist + ): print("urlist类型错误") continue if not isinstance(filepath, str): @@ -153,7 +179,11 @@ if __name__ == '__main__': continue # 启动下载 - file_download(download_url_list=urlist, download_path=filepath, request_proxies=proxies) + file_download( + download_url_list=urlist, + download_path=filepath, + request_proxies=proxies, + ) else: print("Json结构错误") except json.JSONDecodeError: diff --git a/src/Python/asst/emulator.py b/src/Python/asst/emulator.py index 4857a7629e..9d8b7ff8a4 100644 --- a/src/Python/asst/emulator.py +++ b/src/Python/asst/emulator.py @@ -1,11 +1,15 @@ -import time import subprocess +import time class Bluestacks: @staticmethod - def get_hyperv_port(conf_path=r"C:\ProgramData\BlueStacks_nxt\bluestacks.conf", instance_name="Pie64", read_imageinfo_from_config=False) -> int: - """ 获取Hyper-v版蓝叠的adb port + def get_hyperv_port( + conf_path=r"C:\ProgramData\BlueStacks_nxt\bluestacks.conf", + instance_name="Pie64", + read_imageinfo_from_config=False, + ) -> int: + """获取Hyper-v版蓝叠的adb port :param conf_path: bluestacks.conf 的路径+文件名 :param instance_name: 多开的名称,在bluestacks.conf中以类似bst.instance..status.adb_port的形式出现,如Nougat64,Pie64,Pie64_1等 @@ -13,17 +17,25 @@ class Bluestacks: """ with open(conf_path, encoding="UTF-8") as f: configs = { - line.split('=')[0].strip(): line.split('=')[1].strip().strip('"\n') + line.split("=")[0].strip(): line.split("=")[1].strip().strip('"\n') for line in f } if read_imageinfo_from_config: - instances = [i.strip('"') for i in configs['bst.installed_images'].split(',')] + instances = [ + i.strip('"') for i in configs["bst.installed_images"].split(",") + ] instance_name = instances[0] - return int(configs[f'bst.instance.{instance_name}.status.adb_port'].replace('"', "")) + return int( + configs[f"bst.instance.{instance_name}.status.adb_port"].replace('"', "") + ) @staticmethod - def launch_emulator_win(emulator_path=r'C:\Program Files\BlueStacks_nxt\HD-Player.exe', post_delay=30, arg_instance=None): - """ 启动模拟器 + def launch_emulator_win( + emulator_path=r"C:\Program Files\BlueStacks_nxt\HD-Player.exe", + post_delay=30, + arg_instance=None, + ): + """启动模拟器 如需管理员权限启动模拟器则以管理员权限执行Python脚本 :param emulator_path: 模拟器可执行文件路径+文件名 diff --git a/src/Python/asst/updater.py b/src/Python/asst/updater.py index c518d7b452..8d79bb970d 100644 --- a/src/Python/asst/updater.py +++ b/src/Python/asst/updater.py @@ -1,17 +1,17 @@ import json import multiprocessing +import os import platform import re -import os import tarfile import zipfile -from multiprocessing import queues, Process +from multiprocessing import Process, queues from urllib import request from urllib.error import HTTPError, URLError +from . import downloader from .asst import Asst from .utils import Version -from . import downloader class Updater: @@ -44,7 +44,13 @@ class Updater: # 使用子线程获取当前版本后关闭,避免占用dll q = queues.Queue(1, ctx=multiprocessing) - p = Process(target=self._get_cur_version, args=(path, q,)) + p = Process( + target=self._get_cur_version, + args=( + path, + q, + ), + ) p.start() p.join() # MAA当前版本 self.cur_version @@ -53,11 +59,11 @@ class Updater: @staticmethod def map_version_type(version): type_map = { - Version.Nightly: 'alpha', - Version.Beta: 'beta', - Version.Stable: 'stable' + Version.Nightly: "alpha", + Version.Beta: "beta", + Version.Stable: "stable", } - return type_map.get(version, 'stable') + return type_map.get(version, "stable") def get_latest_version(self): """ @@ -92,8 +98,8 @@ class Updater: } """ version_type = self.map_version_type(self.version) - latest_version = response_data[version_type]['version'] - version_detail = response_data[version_type]['detail'] + latest_version = response_data[version_type]["version"] + version_detail = response_data[version_type]["detail"] return latest_version, version_detail except Exception as e: self.custom_print(e) @@ -115,17 +121,17 @@ class Updater: """ system_platform = "win-x64" system = platform.system() - if system == 'Linux': + if system == "Linux": machine = platform.machine() - if machine == 'aarch64': + if machine == "aarch64": # Linux aarch64 system_platform = "linux-aarch64" else: # Linux x86 system_platform = "linux-x86_64" - elif system == 'Windows': + elif system == "Windows": machine = platform.machine() - if machine == 'AMD64' or machine == 'x86_64': + if machine == "AMD64" or machine == "x86_64": # Windows x86-64 system_platform = "win-x64" else: @@ -134,7 +140,7 @@ class Updater: # 请求的是https://api.maa.plus/MaaAssistantArknights/api/version/stable.json,或其他版本类型对应的url detail_json = request.urlopen(detail) detail_data = json.loads(detail_json.read().decode("utf-8")) - assets_list = detail_data["details"]["assets"] # 列表,子元素为字典 + assets_list = detail_data["details"]["assets"] # 列表,子元素为字典 # 找到对应系统和架构的版本 for assets in assets_list: """ @@ -151,7 +157,7 @@ class Updater: ] } """ - assets_name = assets["name"] # 示例值:MAA-v4.24.0-beta.1-win-arm64.zip + assets_name = assets["name"] # 示例值:MAA-v4.24.0-beta.1-win-arm64.zip # 正则匹配(用于选择当前系统及架构的版本) # 在线等一个不这么蠢的方法 pattern = r"^MAA-.*-" + re.escape(system_platform) + r"\.(zip|tar\.gz)$" @@ -174,9 +180,11 @@ class Updater: # 从API获取最新版本 # latest_version:版本号; version_detail:对应的json地址 latest_version, version_detail = self.get_latest_version() - if not latest_version: # latest_version为False代表获取失败 + if not latest_version: # latest_version为False代表获取失败 self.custom_print("获取版本信息失败") - elif current_version == latest_version: # 通过比较二者是否一致判断是否需要更新(摆烂 + elif ( + current_version == latest_version + ): # 通过比较二者是否一致判断是否需要更新(摆烂 self.custom_print("当前为最新版本,无需更新") else: self.custom_print(f"检测到最新版本:{latest_version},正在更新") @@ -200,36 +208,45 @@ class Updater: max_retry = 3 for retry_frequency in range(max_retry): try: - Updater.custom_print("开始下载" + (f",第{retry_frequency}次尝试" if retry_frequency > 1 else "")) + Updater.custom_print( + "开始下载" + + ( + f",第{retry_frequency}次尝试" + if retry_frequency > 1 + else "" + ) + ) # 调用downloader方法进行下载 - download_finished = downloader.file_download(download_url_list=url_list, download_path=file) - break # RNM怎么会有这么蠢的人忘了写break啊淦 - except(HTTPError, URLError) as e: + download_finished = downloader.file_download( + download_url_list=url_list, download_path=file + ) + break # RNM怎么会有这么蠢的人忘了写break啊淦 + except (HTTPError, URLError) as e: Updater.custom_print(e) if not download_finished: - Updater.custom_print('下载异常,更新失败') + Updater.custom_print("下载异常,更新失败") return # 解压下载的文件, - Updater.custom_print('开始安装更新,请不要关闭') + Updater.custom_print("开始安装更新,请不要关闭") file_extension = os.path.splitext(filename)[1] unzip = False # 根据拓展名选择解压算法 # .zip(Windows)/.tar.gz(Linux) - if file_extension == '.zip': - zfile = zipfile.ZipFile(file, 'r') + if file_extension == ".zip": + zfile = zipfile.ZipFile(file, "r") zfile.extractall(self.path) zfile.close() unzip = True # .tar.gz拓展名的情况(按照这个方式得到的拓展名是.gz,但是解压的是tar.gz - elif file_extension == '.gz': - tfile = tarfile.open(file, 'r:gz') + elif file_extension == ".gz": + tfile = tarfile.open(file, "r:gz") tfile.extractall(self.path) tfile.close() unzip = True # 删除压缩包 os.remove(file) if unzip: - Updater.custom_print('更新完成') + Updater.custom_print("更新完成") else: - Updater.custom_print('更新未完成') + Updater.custom_print("更新未完成") diff --git a/src/Python/asst/utils.py b/src/Python/asst/utils.py index 45d11b48ef..91b4785a3b 100644 --- a/src/Python/asst/utils.py +++ b/src/Python/asst/utils.py @@ -1,5 +1,5 @@ -from typing import Union, Dict, List, Any, Type -from enum import Enum, IntEnum, unique, auto +from enum import Enum, IntEnum, auto, unique +from typing import Any, Dict, List, Type, Union JSON = Union[Dict[str, Any], List[Any], int, str, float, bool, Type[None]] @@ -24,6 +24,7 @@ class Message(Enum): 请参考 docs/回调消息.md """ + InternalError = 0 InitFailed = auto() @@ -64,6 +65,7 @@ class Version(Enum): """ 目标版本 """ + Nightly = auto() Beta = auto() diff --git a/src/Python/sample.py b/src/Python/sample.py index ed530d597a..5c7a2e52cb 100644 --- a/src/Python/sample.py +++ b/src/Python/sample.py @@ -3,15 +3,15 @@ import pathlib import time from asst.asst import Asst -from asst.utils import Message, Version, InstanceOptionType -from asst.updater import Updater from asst.emulator import Bluestacks +from asst.updater import Updater +from asst.utils import InstanceOptionType, Message, Version @Asst.CallBackType def my_callback(msg, details, arg): m = Message(msg) - d = json.loads(details.decode('utf-8')) + d = json.loads(details.decode("utf-8")) print(m, d, arg) @@ -58,7 +58,7 @@ if __name__ == "__main__": # 设置额外配置 # 触控方案配置 - asst.set_instance_option(InstanceOptionType.touch_type, 'maatouch') + asst.set_instance_option(InstanceOptionType.touch_type, "maatouch") # 暂停下干员 # asst.set_instance_option(InstanceOptionType.deployment_with_pause, '1') @@ -69,38 +69,49 @@ if __name__ == "__main__": # port = Bluestacks.get_hyperv_port(r"C:\ProgramData\BlueStacks_nxt\bluestacks.conf", "Pie64_1") # 请自行配置 adb 环境变量,或修改为 adb 可执行程序的路径 - if asst.connect('adb.exe', '127.0.0.1:5555'): - print('连接成功') + if asst.connect("adb.exe", "127.0.0.1:5555"): + print("连接成功") else: - print('连接失败') + print("连接失败") exit() # 任务及参数请参考 docs/zh-cn/protocol/integration.md - asst.append_task('StartUp') - asst.append_task('Fight', { - 'stage': '', - 'report_to_penguin': True, - # 'penguin_id': '1234567' - }) - asst.append_task('Recruit', { - 'select': [4], - 'confirm': [3, 4], - 'times': 4 - }) - asst.append_task('Infrast', { - 'facility': [ - "Mfg", "Trade", "Control", "Power", "Reception", "Office", "Dorm" - ], - 'drones': "Money" - }) - asst.append_task('Visit') - asst.append_task('Mall', { - 'shopping': True, - 'buy_first': ['招聘许可', '龙门币'], - 'blacklist': ['家具', '碳'], - }) - asst.append_task('Award') + asst.append_task("StartUp") + asst.append_task( + "Fight", + { + "stage": "", + "report_to_penguin": True, + # 'penguin_id': '1234567' + }, + ) + asst.append_task("Recruit", {"select": [4], "confirm": [3, 4], "times": 4}) + asst.append_task( + "Infrast", + { + "facility": [ + "Mfg", + "Trade", + "Control", + "Power", + "Reception", + "Office", + "Dorm", + ], + "drones": "Money", + }, + ) + asst.append_task("Visit") + asst.append_task( + "Mall", + { + "shopping": True, + "buy_first": ["招聘许可", "龙门币"], + "blacklist": ["家具", "碳"], + }, + ) + asst.append_task("Award") # asst.append_task('Copilot', { # 'filename': './GA-EX8-raid.json', # 'formation': False diff --git a/tools/AutoLocalization/requirements.txt b/tools/AutoLocalization/requirements.txt index f36bfb984a..99fa6654a5 100644 --- a/tools/AutoLocalization/requirements.txt +++ b/tools/AutoLocalization/requirements.txt @@ -4,6 +4,6 @@ Cython>=0.29.25 lxml~=4.9.2 openai~=0.27.7 python-dotenv~=1.0.0 -cchardet~=2.1.7 +charset-normalizer~=3.3.1 xmldiff>=2.6.3 opencc~=1.1.1 diff --git a/tools/AutoLocalization/setup.py b/tools/AutoLocalization/setup.py index afcfcb818d..2cf5f27143 100644 --- a/tools/AutoLocalization/setup.py +++ b/tools/AutoLocalization/setup.py @@ -1,31 +1,30 @@ -from setuptools import setup, find_packages +from setuptools import find_packages, setup setup( - name='AutoLocalization', - version='1.0', - url='', - license='', - author='noctboat', - author_email='65664032+UniMars@users.noreply.github.com', - description='A tool to translate doc into different languages.', - packages=find_packages(where='src'), + name="AutoLocalization", + version="1.0", + url="", + license="", + author="noctboat", + author_email="65664032+UniMars@users.noreply.github.com", + description="A tool to translate doc into different languages.", + packages=find_packages(where="src"), package_dir={"": "src"}, entry_points={ - 'console_scripts': [ - 'auto_localization = auto_localization.cli:main', + "console_scripts": [ + "auto_localization = auto_localization.cli:main", ], }, install_requires=[ - 'setuptools>=67.8.0', - 'wheel>=0.40.0', - 'Cython>=0.29.25', - 'lxml~=4.9.2', - 'openai~=0.27.7', - 'python-dotenv~=1.0.0', - 'cchardet~=2.1.7', - 'xmldiff>=2.6.3', - 'opencc~=1.1.1' + "setuptools>=67.8.0", + "wheel>=0.40.0", + "Cython>=0.29.25", + "lxml~=4.9.2", + "openai~=0.27.7", + "python-dotenv~=1.0.0", + "charset-normalizer~=3.3.1", + "xmldiff>=2.6.3", + "opencc~=1.1.1", ], - python_requires='>3.10', - + python_requires=">3.10", ) diff --git a/tools/AutoLocalization/src/auto_localization/__init__.py b/tools/AutoLocalization/src/auto_localization/__init__.py index f51e782425..dd35a4f3ba 100644 --- a/tools/AutoLocalization/src/auto_localization/__init__.py +++ b/tools/AutoLocalization/src/auto_localization/__init__.py @@ -1,6 +1,13 @@ from .cli import main from .git import get_latest_file_content from .translate import ChatTranslator -from .xaml_load import judge_encoding, parse_lang_str, XamlParser +from .xaml_load import XamlParser, judge_encoding, parse_lang_str -__all__ = ['ChatTranslator', 'judge_encoding', 'parse_lang_str', 'XamlParser', 'get_latest_file_content', 'main'] +__all__ = [ + "ChatTranslator", + "judge_encoding", + "parse_lang_str", + "XamlParser", + "get_latest_file_content", + "main", +] diff --git a/tools/AutoLocalization/src/auto_localization/cli.py b/tools/AutoLocalization/src/auto_localization/cli.py index 68a81768a1..469c24e232 100644 --- a/tools/AutoLocalization/src/auto_localization/cli.py +++ b/tools/AutoLocalization/src/auto_localization/cli.py @@ -1,10 +1,11 @@ import argparse import logging import os - -from shutil import copy from pathlib import Path +from shutil import copy + from dotenv import load_dotenv + from .git import get_latest_file_content from .xaml_load import XamlParser @@ -193,7 +194,9 @@ def update_by_language(test, path, language): def cli_ui(test=None): - parser = argparse.ArgumentParser(description="一个用于自动翻译本地化目录下不同语言文档的命令行工具。") + parser = argparse.ArgumentParser( + description="一个用于自动翻译本地化目录下不同语言文档的命令行工具。" + ) subparsers = parser.add_subparsers() parser_init = subparsers.add_parser("init", help="初始化工具") parser_init.set_defaults(func=initiate) @@ -202,7 +205,9 @@ def cli_ui(test=None): "create", help="初始化其他语言的文档,可选参数:-f --force, -t --test" ) parser_create.set_defaults(func=create) - parser_create.add_argument("-f", "--force", action="store_true", help="强制覆盖已有的部分") + parser_create.add_argument( + "-f", "--force", action="store_true", help="强制覆盖已有的部分" + ) parser_create.add_argument( "-t", "--test", action="store_true", help="测试更新情况(跳过chatgpt)" ) @@ -210,7 +215,9 @@ def cli_ui(test=None): "-l", "--language", help="指定语言,可选参数:en-us, zh-tw, ja-jp, ko-kr" ) - parser_update = subparsers.add_parser("update", help="更新本地化翻译,可选参数:-t --test") + parser_update = subparsers.add_parser( + "update", help="更新本地化翻译,可选参数:-t --test" + ) parser_update.set_defaults(func=update) parser_update.add_argument( "-t", "--test", action="store_true", help="测试更新情况(跳过chatgpt)" diff --git a/tools/AutoLocalization/src/auto_localization/git.py b/tools/AutoLocalization/src/auto_localization/git.py index 6ab49d7b60..c2be08fb50 100644 --- a/tools/AutoLocalization/src/auto_localization/git.py +++ b/tools/AutoLocalization/src/auto_localization/git.py @@ -1,6 +1,7 @@ import os.path import subprocess + def get_latest_file_content(file_path="./cli.py", encoding="utf-8", tag_name=""): dirname = os.path.dirname(file_path) basename = os.path.basename(file_path) diff --git a/tools/AutoLocalization/src/auto_localization/translate.py b/tools/AutoLocalization/src/auto_localization/translate.py index 1301c116bb..bbdf3f8f53 100644 --- a/tools/AutoLocalization/src/auto_localization/translate.py +++ b/tools/AutoLocalization/src/auto_localization/translate.py @@ -3,12 +3,12 @@ import logging import os import re import time -import openai - -from pathlib import Path from json import JSONDecodeError +from pathlib import Path + +import openai from dotenv import load_dotenv -from openai.error import RateLimitError, AuthenticationError +from openai.error import AuthenticationError, RateLimitError from opencc import OpenCC logging.basicConfig( diff --git a/tools/AutoLocalization/src/auto_localization/xaml_load.py b/tools/AutoLocalization/src/auto_localization/xaml_load.py index 2d69a65acf..37542003c0 100644 --- a/tools/AutoLocalization/src/auto_localization/xaml_load.py +++ b/tools/AutoLocalization/src/auto_localization/xaml_load.py @@ -1,12 +1,13 @@ import logging import os import re - from copy import deepcopy -from cchardet import detect + +from charset_normalizer import from_bytes from lxml import etree from xmldiff import main -from xmldiff.actions import UpdateTextIn, InsertComment, UpdateTextAfter, DeleteNode +from xmldiff.actions import DeleteNode, InsertComment, UpdateTextAfter, UpdateTextIn + from .translate import ChatTranslator SPACE = "{http://www.w3.org/XML/1998/namespace}space" @@ -19,8 +20,11 @@ logging.basicConfig( def judge_encoding(file): with open(file, "rb") as _: content = _.read() - result = detect(content) - return result["encoding"] + best_guess = from_bytes(content).best() + if best_guess is None: + # fallback + return "utf-8" + return best_guess.encoding def parse_lang_str(doc_path): diff --git a/tools/AutoLocalization/tests/__init__.py b/tools/AutoLocalization/tests/__init__.py index b0447af6f7..9cbf41e6b4 100644 --- a/tools/AutoLocalization/tests/__init__.py +++ b/tools/AutoLocalization/tests/__init__.py @@ -2,4 +2,4 @@ from _test_all import TestAll from test_translate import TestChatTranslator from test_xaml_load import TestXamlParser -__all__ = ['TestAll', 'TestChatTranslator', 'TestXamlParser'] +__all__ = ["TestAll", "TestChatTranslator", "TestXamlParser"] diff --git a/tools/AutoLocalization/tests/_test_all.py b/tools/AutoLocalization/tests/_test_all.py index 49891dd54a..49fa12cfc6 100644 --- a/tools/AutoLocalization/tests/_test_all.py +++ b/tools/AutoLocalization/tests/_test_all.py @@ -1,41 +1,45 @@ import os.path import unittest -from src.auto_localization import XamlParser, ChatTranslator, parse_lang_str +from src.auto_localization import ChatTranslator, XamlParser, parse_lang_str class TestAll(unittest.TestCase): def setUp(self) -> None: - self.zh_sample_path = '../example/zh-cn.xaml' - self.en_sample_path = '../example/en-us.xaml' + self.zh_sample_path = "../example/zh-cn.xaml" + self.en_sample_path = "../example/en-us.xaml" print(os.path.abspath(self.zh_sample_path)) - with open(self.zh_sample_path, 'r', encoding='utf-8') as f: + with open(self.zh_sample_path, "r", encoding="utf-8") as f: self.zh_sample_content = f.read() - with open(self.en_sample_path, 'r', encoding='utf-8') as f: + with open(self.en_sample_path, "r", encoding="utf-8") as f: self.en_sample_content = f.read() - self.zh_path = 'data/zh-cn.xaml' - self.en_force_path = 'data/en-us_force.xaml' - with open(self.zh_path, 'w', encoding='utf-8') as f: + self.zh_path = "data/zh-cn.xaml" + self.en_force_path = "data/en-us_force.xaml" + with open(self.zh_path, "w", encoding="utf-8") as f: f.write(self.zh_sample_content) - with open(self.en_force_path, 'w', encoding='utf-8') as f: + with open(self.en_force_path, "w", encoding="utf-8") as f: f.write(self.en_sample_content) target_language = parse_lang_str(self.en_force_path) base_language = parse_lang_str(self.zh_path) - self.chat = ChatTranslator(language=target_language, base_language=base_language) + self.chat = ChatTranslator( + language=target_language, base_language=base_language + ) def test_translate_force(self): count_success = 0 count_fail = 0 zh_parser = XamlParser(parse_type=0, file=self.zh_path) - for i in zh_parser.tree.findall('.//s:String[@x:Key]', namespaces=zh_parser.nsmap): + for i in zh_parser.tree.findall( + ".//s:String[@x:Key]", namespaces=zh_parser.nsmap + ): text = self.chat.translate(i.text) if text is None: count_fail += 1 else: count_success += 1 - print(f'count_success: {count_success}, count_fail: {count_fail}') + print(f"count_success: {count_success}, count_fail: {count_fail}") self.assertGreater(0, count_fail) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tools/AutoLocalization/tests/test_translate.py b/tools/AutoLocalization/tests/test_translate.py index 644716b044..ad0db5c2a9 100644 --- a/tools/AutoLocalization/tests/test_translate.py +++ b/tools/AutoLocalization/tests/test_translate.py @@ -8,13 +8,13 @@ class TestChatTranslator(unittest.TestCase): def setUp(self): self.translator = ChatTranslator() - @patch('openai.ChatCompletion.create') + @patch("openai.ChatCompletion.create") def test_translate_default_sentence(self, mock_create): mock_create.return_value = { - 'choices': [ + "choices": [ { - 'message': { - 'content': """{"message":200,"content":"Tips: \\n \\n \n 1. Please use this function on the interface with the 'Start Action' button; \\n \\n \n 2. Using a friend's assistance can turn off 'Auto Formation' and manually select operators before starting; \\n \\n \n 3. To conduct a simulation of the paradox, turn off 'Auto Formation', select the skills, and then start on the 'Start Simulation' button interface; \\n \\n \n 4. For 'Annihilation', multiple tasks are built-in under the 'resource/copilot' folder. Please manually form a squad and start on the 'Start Deployment' interface (can be used with 'number of loops'); \\n \\n \n 5. Video recognition is now supported. Please drag the strategy video file and then start. The video resolution should be 16:9, without black borders, simulator borders, or other interfering elements."}""" + "message": { + "content": """{"message":200,"content":"Tips: \\n \\n \n 1. Please use this function on the interface with the 'Start Action' button; \\n \\n \n 2. Using a friend's assistance can turn off 'Auto Formation' and manually select operators before starting; \\n \\n \n 3. To conduct a simulation of the paradox, turn off 'Auto Formation', select the skills, and then start on the 'Start Simulation' button interface; \\n \\n \n 4. For 'Annihilation', multiple tasks are built-in under the 'resource/copilot' folder. Please manually form a squad and start on the 'Start Deployment' interface (can be used with 'number of loops'); \\n \\n \n 5. Video recognition is now supported. Please drag the strategy video file and then start. The video resolution should be 16:9, without black borders, simulator borders, or other interfering elements."}""" } } ] @@ -27,13 +27,13 @@ class TestChatTranslator(unittest.TestCase): self.assertEqual(length, 16) self.assertEqual(result, assert_result) - @patch('openai.ChatCompletion.create') + @patch("openai.ChatCompletion.create") def test_translate_custom_sentence(self, mock_create): mock_create.return_value = { - 'choices': [ + "choices": [ { - 'message': { - 'content': '{"message":200,"content":"Custom translated text"}' + "message": { + "content": '{"message":200,"content":"Custom translated text"}' } } ] @@ -42,51 +42,37 @@ class TestChatTranslator(unittest.TestCase): result = self.translator.translate(sentence="This is a custom sentence") self.assertEqual(result, "Custom translated text") - @patch('openai.ChatCompletion.create') + @patch("openai.ChatCompletion.create") def test_translate_unknown_language(self, mock_create): mock_create.return_value = { - 'choices': [ - { - 'message': { - 'content': '{"message":404,"content":"未知语言"}' - } - } + "choices": [ + {"message": {"content": '{"message":404,"content":"未知语言"}'}} ] } result = self.translator.translate(target_language="未知") self.assertIsNone(result) - @patch('openai.ChatCompletion.create') + @patch("openai.ChatCompletion.create") def test_translate_error(self, mock_create): mock_create.return_value = { - 'choices': [ - { - 'message': { - 'content': '{"message":500,"content":"内部服务器错误"}' - } - } + "choices": [ + {"message": {"content": '{"message":500,"content":"内部服务器错误"}'}} ] } result = self.translator.translate() self.assertIsNone(result) - @patch('openai.ChatCompletion.create') + @patch("openai.ChatCompletion.create") def test_wrong_input_error(self, mock_create): mock_create.return_value = { - 'choices': [ - { - 'message': { - 'content': '我不明白你在说什么' - } - } - ] + "choices": [{"message": {"content": "我不明白你在说什么"}}] } result = self.translator.translate() self.assertIsNone(result) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tools/AutoLocalization/tests/test_xaml_load.py b/tools/AutoLocalization/tests/test_xaml_load.py index 16ade913fb..f8328bb530 100644 --- a/tools/AutoLocalization/tests/test_xaml_load.py +++ b/tools/AutoLocalization/tests/test_xaml_load.py @@ -1,54 +1,54 @@ import os import unittest -from src.auto_localization import judge_encoding, parse_lang_str, XamlParser +from src.auto_localization import XamlParser, judge_encoding, parse_lang_str class TestXamlParser(unittest.TestCase): def setUp(self): - self.zh_sample_path = 'example/zh-cn.xaml' - self.zh_new_sample_path = 'example/zh-cn_new.xaml' - self.en_sample_path = 'example/en-us.xaml' - self.en_force_sample_path = 'example/en-us_force.xaml' - self.en_compare_sample_path = 'example/en-us_compare.xaml' - self.en_update_sample_path = 'example/en-us_update.xaml' + self.zh_sample_path = "example/zh-cn.xaml" + self.zh_new_sample_path = "example/zh-cn_new.xaml" + self.en_sample_path = "example/en-us.xaml" + self.en_force_sample_path = "example/en-us_force.xaml" + self.en_compare_sample_path = "example/en-us_compare.xaml" + self.en_update_sample_path = "example/en-us_update.xaml" os.path.abspath(self.zh_sample_path) - with open(self.zh_sample_path, 'r', encoding='utf-8') as f: + with open(self.zh_sample_path, "r", encoding="utf-8") as f: self.zh_sample_content = f.read() - with open(self.zh_new_sample_path, 'r', encoding='utf-8') as f: + with open(self.zh_new_sample_path, "r", encoding="utf-8") as f: self.zh_new_sample_content = f.read() - with open(self.en_sample_path, 'r', encoding='utf-8') as f: + with open(self.en_sample_path, "r", encoding="utf-8") as f: self.en_sample_content = f.read() - with open(self.en_force_sample_path, 'r', encoding='utf-8') as f: + with open(self.en_force_sample_path, "r", encoding="utf-8") as f: self.en_force_sample_content = f.read() - with open(self.en_compare_sample_path, 'r', encoding='utf-8') as f: + with open(self.en_compare_sample_path, "r", encoding="utf-8") as f: self.en_compare_sample_content = f.read() - with open(self.en_update_sample_path, 'r', encoding='utf-8') as f: + with open(self.en_update_sample_path, "r", encoding="utf-8") as f: self.en_update_sample_content = f.read() - if not os.path.exists('tests/data'): - os.makedirs('tests/data') - self.zh_path = 'tests/data/zh-cn.xaml' - self.zh_new_path = 'tests/data/zh-cn_new.xaml' - self.en_force_path = 'tests/data/en-us_force.xaml' - self.en_compare_path = 'tests/data/en-us_compare.xaml' - self.en_update_path = 'tests/data/en-us_update.xaml' - self.zh_tw_path = 'tests/data/zh-tw.xaml' - self.ja_path = 'tests/data/ja-jp.xaml' - self.ko_path = 'tests/data/ko-kr.xaml' - with open(self.zh_path, 'w', encoding='utf-8') as f: + if not os.path.exists("tests/data"): + os.makedirs("tests/data") + self.zh_path = "tests/data/zh-cn.xaml" + self.zh_new_path = "tests/data/zh-cn_new.xaml" + self.en_force_path = "tests/data/en-us_force.xaml" + self.en_compare_path = "tests/data/en-us_compare.xaml" + self.en_update_path = "tests/data/en-us_update.xaml" + self.zh_tw_path = "tests/data/zh-tw.xaml" + self.ja_path = "tests/data/ja-jp.xaml" + self.ko_path = "tests/data/ko-kr.xaml" + with open(self.zh_path, "w", encoding="utf-8") as f: f.write(self.zh_sample_content) - with open(self.zh_new_path, 'w', encoding='utf-8') as f: + with open(self.zh_new_path, "w", encoding="utf-8") as f: f.write(self.zh_new_sample_content) - with open(self.en_force_path, 'w', encoding='utf-8') as f: + with open(self.en_force_path, "w", encoding="utf-8") as f: f.write(self.en_sample_content) - with open(self.en_compare_path, 'w', encoding='utf-8') as f: + with open(self.en_compare_path, "w", encoding="utf-8") as f: f.write(self.en_sample_content) - with open(self.en_update_path, 'w', encoding='utf-8') as f: + with open(self.en_update_path, "w", encoding="utf-8") as f: f.write(self.en_sample_content) def test_judge_encoding(self): - expected_encoding = 'UTF-8' + expected_encoding = "UTF-8" result_encoding = judge_encoding(self.zh_path) self.assertEqual(expected_encoding, result_encoding) @@ -72,7 +72,9 @@ class TestXamlParser(unittest.TestCase): zh_parser = XamlParser(parse_type=0, file=self.zh_path) with self.assertRaises(AssertionError): XamlParser(parse_type=1, xaml_string=self.zh_sample_content) - zh_string_parser = XamlParser(parse_type=1, language='Chinese', xaml_string=self.zh_sample_content) + zh_string_parser = XamlParser( + parse_type=1, language="Chinese", xaml_string=self.zh_sample_content + ) self.assertIsInstance(zh_parser, XamlParser) self.assertIsInstance(zh_string_parser, XamlParser) self.assertFalse(zh_string_parser.write_xaml()) @@ -81,19 +83,21 @@ class TestXamlParser(unittest.TestCase): with self.assertRaises(AssertionError): XamlParser(parse_type=0, file="./test/blah.xaml") s = zh_parser.tostring - self.assertTrue(s.count(' ') == 0) + self.assertTrue(s.count(" ") == 0) def test_xpath(self): zh_parser = XamlParser(parse_type=0, file=self.zh_sample_path) # 检验空结果 with self.assertRaises(AssertionError): - next(zh_parser.xpath('.//test')) - self.assertIsNone(next(zh_parser.xpath('.//test', accept_empty=True))) + next(zh_parser.xpath(".//test")) + self.assertIsNone(next(zh_parser.xpath(".//test", accept_empty=True))) # 检验多结果 with self.assertRaises(AssertionError): - next(zh_parser.xpath('.//s:String[@x:Key]')) - self.assertLess(1, len(list(zh_parser.xpath('.//s:String[@x:Key]', only_one=False)))) + next(zh_parser.xpath(".//s:String[@x:Key]")) + self.assertLess( + 1, len(list(zh_parser.xpath(".//s:String[@x:Key]", only_one=False))) + ) # 检验单结果 res = list(zh_parser.xpath('.//s:String[@x:Key="Settings"]')) @@ -110,7 +114,7 @@ class TestXamlParser(unittest.TestCase): def test_translate_force(self): zh_parser = XamlParser(parse_type=0, file=self.zh_path) zh_parser.translate_force(self.en_force_path, skip_translate=True) - with open(self.en_force_path, 'r', encoding='utf-8') as f: + with open(self.en_force_path, "r", encoding="utf-8") as f: translated_content = f.read() compare_parser = XamlParser(parse_type=0, file=self.en_force_path) self.assertEqual(translated_content, self.en_force_sample_content) @@ -122,7 +126,7 @@ class TestXamlParser(unittest.TestCase): en_parser.translate_compare(zh_parser, skip_translate=True) - with open(self.en_compare_path, 'r', encoding='utf-8') as f: + with open(self.en_compare_path, "r", encoding="utf-8") as f: # translated_content = f.read() compare_parser = XamlParser(parse_type=0, file=self.en_compare_path) # self.assertEqual(translated_content, self.en_compare_sample_content) @@ -136,12 +140,12 @@ class TestXamlParser(unittest.TestCase): en_parser.update_translate(zh_parser, zh_new_parser, skip_translate=True) en_new_parser.update_translate(zh_parser, zh_new_parser, skip_translate=True) - with open(self.en_update_path, 'r', encoding='utf-8') as f: + with open(self.en_update_path, "r", encoding="utf-8") as f: # translated_content = f.read() compare_parser = XamlParser(parse_type=0, file=self.en_update_path) # self.assertEqual(translated_content, self.en_update_sample_content) self.assertTrue(zh_new_parser.compare_structure(compare_parser)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tools/ChangelogGenerator/changelog_generator.py b/tools/ChangelogGenerator/changelog_generator.py index fdb7f326ce..9308607db6 100644 --- a/tools/ChangelogGenerator/changelog_generator.py +++ b/tools/ChangelogGenerator/changelog_generator.py @@ -1,14 +1,14 @@ +import json +import os +import re +import urllib.error +import urllib.request from argparse import ArgumentParser from enum import Enum -from typing import Tuple from pathlib import Path -import os -import json -import re -import urllib.request -import urllib.error +from typing import Tuple -repo = "MaaAssistantArknights/MaaAssistantArknights" # Owner/RepoName +repo = "MaaAssistantArknights/MaaAssistantArknights" # Owner/RepoName cur_dir = Path(__file__).parent contributors_path = cur_dir / "contributors.json" changelog_path = cur_dir.parent.parent / "CHANGELOG.md" @@ -17,7 +17,9 @@ with_hash = False with_commitizen = False committer_is_author = False merge_author = False -commitizens = r"(?:build|chore|ci|docs?|feat!?|fix|perf|refactor|rft|style|test|i18n|typo|debug)" +commitizens = ( + r"(?:build|chore|ci|docs?|feat!?|fix|perf|refactor|rft|style|test|i18n|typo|debug)" +) ignore_commitizens = r"(?:build|ci|style|debug)" contributors = {} @@ -205,8 +207,8 @@ def build_commits_tree(commit_hash: str): def retry_urlopen(*args, **kwargs): - import time import http.client + import time for _ in range(5): try: @@ -290,7 +292,9 @@ def main(tag_name=None, latest=None): # In case the check step fails in the workflow, prevent exit error 1 if raw_gitlogs.strip(): for raw_commit_info in raw_gitlogs.split("\n\n"): - commit_hash, author, committer, message, parent = raw_commit_info.split("\n") + commit_hash, author, committer, message, parent = raw_commit_info.split( + "\n" + ) author = convert_contributors_name( name=author, commit_hash=commit_hash, name_type="author" @@ -315,7 +319,9 @@ def main(tag_name=None, latest=None): for commit_hash in raw_gitlogs.split("\n"): if commit_hash not in raw_commits_info: continue - git_addition_command = rf'git log {commit_hash} --no-walk --pretty=format:"%b"' + git_addition_command = ( + rf'git log {commit_hash} --no-walk --pretty=format:"%b"' + ) addition = call_command(git_addition_command) coauthors = [] for coauthor in re.findall(r"Co-authored-by: (.*) <(?:.*)>", addition): @@ -327,23 +333,21 @@ def main(tag_name=None, latest=None): print(f"Cannot get coauthor: {coauthor}.") raw_commits_info[commit_hash]["coauthors"] = coauthors - git_skip_command = ( - rf'git log {latest}..HEAD --pretty=format:"%H%n" --grep="\[skip changelog\]"' - ) + git_skip_command = rf'git log {latest}..HEAD --pretty=format:"%H%n" --grep="\[skip changelog\]"' raw_gitlogs = call_command(git_skip_command) for commit_hash in raw_gitlogs.split("\n\n"): if commit_hash not in raw_commits_info: continue - git_show_command = ( - rf'git show -s --format=%B%n {commit_hash}' - ) + git_show_command = rf"git show -s --format=%B%n {commit_hash}" raw_git_shows = call_command(git_show_command) for commit_body in raw_git_shows.split("\n"): - if not commit_body.startswith("* ") and "[skip changelog]" in commit_body: + if ( + not commit_body.startswith("* ") + and "[skip changelog]" in commit_body + ): raw_commits_info[commit_hash]["skip"] = True - # print(json.dumps(raw_commits_info, ensure_ascii=False, indent=2)) res = print_commits(build_commits_tree([x for x in raw_commits_info.keys()][0])) @@ -359,7 +363,9 @@ def main(tag_name=None, latest=None): # In case the check step fails in the workflow, prevent exit error 1 else: print("No commits found.") - with open(os.getenv('GITHUB_OUTPUT'), 'a') as github_output: github_output.write("cancel_run=true\n") + with open(os.getenv("GITHUB_OUTPUT"), "a") as github_output: + github_output.write("cancel_run=true\n") + def ArgParser(): parser = ArgumentParser() diff --git a/tools/ClangFormatter/clang-formatter.py b/tools/ClangFormatter/clang-formatter.py index 27b2c57ebb..20466b3312 100644 --- a/tools/ClangFormatter/clang-formatter.py +++ b/tools/ClangFormatter/clang-formatter.py @@ -1,16 +1,33 @@ -from argparse import ArgumentParser import json import os +from argparse import ArgumentParser + def ArgParser(): parser = ArgumentParser() parser.add_argument("--input", help="input dir", metavar="I", dest="src") - parser.add_argument("--clang-format", help="the path of clang-format.exe", metavar="PATH", dest="exe", default="clang-format") - parser.add_argument("--style", help="clang-format style", dest="style", default="file") - parser.add_argument("--rule", help="json-style '.xxx' array", dest="rule", default="[\".c\", \".h\", \".cpp\", \".hpp\"]") - parser.add_argument("--ignore", help="json-style path array", dest="ignore", default="[]") + parser.add_argument( + "--clang-format", + help="the path of clang-format.exe", + metavar="PATH", + dest="exe", + default="clang-format", + ) + parser.add_argument( + "--style", help="clang-format style", dest="style", default="file" + ) + parser.add_argument( + "--rule", + help="json-style '.xxx' array", + dest="rule", + default='[".c", ".h", ".cpp", ".hpp"]', + ) + parser.add_argument( + "--ignore", help="json-style path array", dest="ignore", default="[]" + ) return parser + if __name__ == "__main__": args = ArgParser().parse_args() clang_format_exe = args.exe @@ -37,7 +54,12 @@ if __name__ == "__main__": print("Invalid rule!") else: for root, dirs, files in os.walk(input_path): - if any([os.path.normpath(root).startswith(ignore_dir) for ignore_dir in ignore_dirs]): + if any( + [ + os.path.normpath(root).startswith(ignore_dir) + for ignore_dir in ignore_dirs + ] + ): continue for f in files: file = os.path.join(root, f) @@ -45,11 +67,11 @@ if __name__ == "__main__": continue if os.path.splitext(file)[-1] in rule_array: print(file) - os.system(f"{clang_format_exe} -i -style={args.style} \"{file}\"") + os.system(f'{clang_format_exe} -i -style={args.style} "{file}"') elif os.path.isfile(input_path): file = input_path print(file) - os.system(f"{clang_format_exe} -i -style={args.style} \"{file}\"") + os.system(f'{clang_format_exe} -i -style={args.style} "{file}"') else: print("Invalid input_path!") @@ -57,4 +79,4 @@ r""" example: python tools\ClangFormatter\clang-formatter.py --input=resource\ --ignore="[\"resource/Arknights-Tile-Pos\", \"resource/infrast.json\"]" python tools\ClangFormatter\clang-formatter.py --input=src\MaaCore -""" \ No newline at end of file +""" diff --git a/tools/CropRoi/main.py b/tools/CropRoi/main.py index 625ab8de78..c1a93bd5e6 100644 --- a/tools/CropRoi/main.py +++ b/tools/CropRoi/main.py @@ -8,7 +8,7 @@ except ImportError: exit(1) from pathlib import Path -from typing import Tuple, Optional +from typing import Optional, Tuple class RoiCropper: @@ -106,7 +106,7 @@ class RoiCropper: ) # 添加操作提示 - #self._draw_instructions(display) + # self._draw_instructions(display) cv2.imshow("ROI Cropper", display) diff --git a/tools/GetImageFromROI/cutter.py b/tools/GetImageFromROI/cutter.py index 124a8cf849..f205ff7bf5 100644 --- a/tools/GetImageFromROI/cutter.py +++ b/tools/GetImageFromROI/cutter.py @@ -1,7 +1,8 @@ -import cv2 import json from pathlib import Path +import cv2 + """ This is a tool for cropping one image into several images based on current roi. Use this tool when a raw image contains many templates. @@ -16,10 +17,30 @@ std_ratio = std_width / std_height task_paths = { "CN": Path(__file__).parent.parent.parent / "resource" / "tasks", - "twxy": Path(__file__).parent.parent.parent / "resource" / "global" / "txwy" / "resource" / "tasks", - "YoStarEN": Path(__file__).parent.parent.parent / "resource" / "global" / "YoStarEN" / "resource" / "tasks", - "YoStarJP": Path(__file__).parent.parent.parent / "resource" / "global" / "YoStarJP" / "resource" / "tasks", - "YoStarKR": Path(__file__).parent.parent.parent / "resource" / "global" / "YoStarKR" / "resource" / "tasks" + "twxy": Path(__file__).parent.parent.parent + / "resource" + / "global" + / "txwy" + / "resource" + / "tasks", + "YoStarEN": Path(__file__).parent.parent.parent + / "resource" + / "global" + / "YoStarEN" + / "resource" + / "tasks", + "YoStarJP": Path(__file__).parent.parent.parent + / "resource" + / "global" + / "YoStarJP" + / "resource" + / "tasks", + "YoStarKR": Path(__file__).parent.parent.parent + / "resource" + / "global" + / "YoStarKR" + / "resource" + / "tasks", } # Change this to your client @@ -31,15 +52,15 @@ task_file = task_paths["CN"] # # For example, when adding a new homepage theme: task_list = [ - "Award", # Task.png - "GachaEnter", # GachaEnter.png - "Home", # Terminal.png - "Infrast", # EnterInfrast.png - "OperBoxEnter", # OperBoxEnter.png - "Recruit", # Recruit.png - "Visit", # Friends.png - "DepotEnter", # DepotEnter.png - "Mall", # Mall.png + "Award", # Task.png + "GachaEnter", # GachaEnter.png + "Home", # Terminal.png + "Infrast", # EnterInfrast.png + "OperBoxEnter", # OperBoxEnter.png + "Recruit", # Recruit.png + "Visit", # Friends.png + "DepotEnter", # DepotEnter.png + "Mall", # Mall.png ] src_path = Path(__file__).parent / "src" diff --git a/tools/GetImageFromROI/updater.py b/tools/GetImageFromROI/updater.py index 21b17a5ece..b62b0d8c02 100644 --- a/tools/GetImageFromROI/updater.py +++ b/tools/GetImageFromROI/updater.py @@ -1,6 +1,7 @@ import json from pathlib import Path -from cutter import task_paths, task_list, src_path, dst_path + +from cutter import dst_path, src_path, task_list, task_paths """ Update tasks.json for multi template tasks diff --git a/tools/ImageCoordinate/coordinate.py b/tools/ImageCoordinate/coordinate.py index e62872ad86..4fb0f104cc 100644 --- a/tools/ImageCoordinate/coordinate.py +++ b/tools/ImageCoordinate/coordinate.py @@ -1,7 +1,8 @@ -from PIL import Image, ImageTk +import argparse import tkinter as tk from tkinter import simpledialog -import argparse + +from PIL import Image, ImageTk # predifined image paths (for testing) imgs = [] @@ -12,6 +13,7 @@ KEEP_RECT = True # The prompt message PROMPT_TEXT = "Press 'q': quit, 'n': next image, 't': toggle text, 's': save last rect, 'c': clear all, 'i': input coords" + # resize the image to 1280x720. If the image is 16:9, scale it; if not, stretch it and return a false flag def resize_image(image): # Get the width and height of the image @@ -26,6 +28,7 @@ def resize_image(image): image = image.resize((1280, 720), Image.BICUBIC) return image, False + class ImageRectSelector: def __init__(self, image_path): # Load the image using PIL @@ -43,14 +46,26 @@ class ImageRectSelector: # Create a Canvas widget and display the photo image on it (leave some space below for the prompt message) self.canvas = tk.Canvas( - self.root, width=self.image.width, height=self.image.height + 20, cursor="tcross") + self.root, + width=self.image.width, + height=self.image.height + 20, + cursor="tcross", + ) self.canvas.pack() self.canvas_image = self.canvas.create_image( - 0, 0, anchor=tk.NW, image=self.tk_image) + 0, 0, anchor=tk.NW, image=self.tk_image + ) # Print the prompt message below the image - self.canvas.create_text(0, self.image.height + 20, text=PROMPT_TEXT, fill="black", anchor=tk.SW, - tags="prompt", font=("Helvetica", 14)) + self.canvas.create_text( + 0, + self.image.height + 20, + text=PROMPT_TEXT, + fill="black", + anchor=tk.SW, + tags="prompt", + font=("Helvetica", 14), + ) # Bind the mouse event handlers to the Canvas widget self.canvas.bind("", self.on_mouse_down) @@ -91,7 +106,12 @@ class ImageRectSelector: # Crop and save the last drawn rectangle def save_rect(self): # Get the coordinates of the rectangle - x1, y1, x2, y2 = self.rect_start_x, self.rect_start_y, self.rect_end_x, self.rect_end_y + x1, y1, x2, y2 = ( + self.rect_start_x, + self.rect_start_y, + self.rect_end_x, + self.rect_end_y, + ) # Get the height and width of the rectangle w, h = x2 - x1, y2 - y1 @@ -111,8 +131,14 @@ class ImageRectSelector: self.canvas.delete("rect") # Draw the rectangle with the given tags - self.canvas.create_rectangle(self.rect_start_x, self.rect_start_y, self.rect_end_x, self.rect_end_y, - outline='red', tags=tags) + self.canvas.create_rectangle( + self.rect_start_x, + self.rect_start_y, + self.rect_end_x, + self.rect_end_y, + outline="red", + tags=tags, + ) def on_mouse_down(self, event): self.rect_start_x, self.rect_start_y = event.x, event.y @@ -132,12 +158,28 @@ class ImageRectSelector: print(coords) # Create a background rectangle for the text widget - self.canvas.create_rectangle(self.rect_start_x, self.rect_start_y, self.rect_start_x + 130, self.rect_start_y + 20, - fill="white", outline="white", tags="text", state=tk.HIDDEN if self.is_text_hidden else tk.NORMAL) + self.canvas.create_rectangle( + self.rect_start_x, + self.rect_start_y, + self.rect_start_x + 130, + self.rect_start_y + 20, + fill="white", + outline="white", + tags="text", + state=tk.HIDDEN if self.is_text_hidden else tk.NORMAL, + ) # Create a text widget with white background to display the rectangle coordinates on the canvas - self.canvas.create_text(self.rect_start_x, self.rect_start_y, text=coords, - fill="black", anchor=tk.NW, tags="text", font=("Helvetica", 10), state=tk.HIDDEN if self.is_text_hidden else tk.NORMAL) + self.canvas.create_text( + self.rect_start_x, + self.rect_start_y, + text=coords, + fill="black", + anchor=tk.NW, + tags="text", + font=("Helvetica", 10), + state=tk.HIDDEN if self.is_text_hidden else tk.NORMAL, + ) def on_key(self, event): # Handle the 'q' key to quit the program @@ -179,8 +221,9 @@ class ImageRectSelector: def prompt_rect_coords(self): # Prompt the user to enter the rectangle coordinates coords_str = simpledialog.askstring( - "Input", "Enter rectangle coordinates (x1 y1 x2 y2):") - x, y, w, h = map(int, coords_str.replace(',', ' ').split()) + "Input", "Enter rectangle coordinates (x1 y1 x2 y2):" + ) + x, y, w, h = map(int, coords_str.replace(",", " ").split()) # Set the rectangle coordinates self.rect_start_x, self.rect_start_y = x, y @@ -189,7 +232,9 @@ class ImageRectSelector: def run(self): # If the image is not 16:9, show a message box and continue if not self.is_16_9: - tk.messagebox.showinfo("Warning", "The image is not 16:9! Proceeding to next image...") + tk.messagebox.showinfo( + "Warning", "The image is not 16:9! Proceeding to next image..." + ) self.root.destroy() return @@ -213,11 +258,10 @@ if __name__ == "__main__": os.chdir(current_dir_path) # Define command-line arguments - parser = argparse.ArgumentParser( - description='Select a rectangle on an image.') - parser.add_argument('image_paths', type=str, - nargs='*', - help='Path to the input image file.') + parser = argparse.ArgumentParser(description="Select a rectangle on an image.") + parser.add_argument( + "image_paths", type=str, nargs="*", help="Path to the input image file." + ) # Parse command-line arguments args = parser.parse_args() @@ -228,9 +272,8 @@ if __name__ == "__main__": elif imgs: image_paths = imgs else: - imgs = simpledialog.askstring( - "Input", "Enter image path(s):") - image_paths = imgs.replace(',', ' ').split() + imgs = simpledialog.askstring("Input", "Enter image path(s):") + image_paths = imgs.replace(",", " ").split() # Print the prompt print(PROMPT_TEXT) diff --git a/tools/InfrastEfficientCheck/InfrastEfficientCheck.py b/tools/InfrastEfficientCheck/InfrastEfficientCheck.py index 613ac4403c..3b7fc51bc4 100644 --- a/tools/InfrastEfficientCheck/InfrastEfficientCheck.py +++ b/tools/InfrastEfficientCheck/InfrastEfficientCheck.py @@ -1,36 +1,38 @@ import json + def find_skills_without_efficient(json_data): """ 分析JSON数据,找出所有设施中没有efficient字段的技能 """ results = {} - + # 遍历所有设施 for facility, facility_data in json_data.items(): # 检查是否有skills字段 - if 'skills' in facility_data: + if "skills" in facility_data: skills_without_efficient = [] - + # 遍历该设施的所有技能 - for skill_id, skill_data in facility_data['skills'].items(): + for skill_id, skill_data in facility_data["skills"].items(): # 检查技能是否有efficient字段 - if 'efficient' not in skill_data: + if "efficient" not in skill_data: skill_info = { - 'id': skill_id, - 'name': skill_data.get('name', ['未知名称'])[0] # 取第一个名称 + "id": skill_id, + "name": skill_data.get("name", ["未知名称"])[0], # 取第一个名称 } skills_without_efficient.append(skill_info) - + # 如果该设施有缺少efficient的技能,添加到结果中 if skills_without_efficient: results[facility] = skills_without_efficient - + return results + def main(): try: - with open('../../resource/infrast.json', 'r', encoding='utf-8') as file: + with open("../../resource/infrast.json", "r", encoding="utf-8") as file: data = json.load(file) except FileNotFoundError: print("未找到 infrast.json 文件") @@ -38,24 +40,25 @@ def main(): except json.JSONDecodeError: print("错误:JSON 文件格式不正确") return - + # 分析数据 missing_efficient_skills = find_skills_without_efficient(data) - + # 输出结果 if not missing_efficient_skills: print("所有技能都有 efficient 字段") else: print("缺少 efficient 字段的技能:") print("=" * 50) - + for facility, skills in missing_efficient_skills.items(): print(f"\n设施: {facility}") print("-" * 30) - + for skill in skills: print(f"技能 ID: {skill['id']}") print(f"技能名称: {skill['name']}") print() -main() \ No newline at end of file + +main() diff --git a/tools/MaskRangeTool/main.py b/tools/MaskRangeTool/main.py index a01cb3e120..e048ee3182 100644 --- a/tools/MaskRangeTool/main.py +++ b/tools/MaskRangeTool/main.py @@ -1,19 +1,27 @@ -import cv2 -from utils import generate_mask_ranges, show_image_mask, calc_mask_from_ranges, compare_2_image_with_mask_ranges from pathlib import Path +import cv2 +from mask_utils import ( + calc_mask_from_ranges, + compare_2_image_with_mask_ranges, + generate_mask_ranges, + show_image_mask, +) + cur_dir = Path(__file__).parent.resolve() maa_dir = cur_dir.parent.parent -if __name__ == '__main__': - luv_base_mask_range_ignore_light = [[[0, 0, 0], [230, 255, 255]]] # 忽略亮色背景 - luv_base_mask_range_ignore_dark = [[[20, 0, 0], [255, 255, 255]]] # 忽略暗色背景 - luv_base_mask_range_ignore_light_dark = [[[20, 0, 0], [230, 255, 255]]] # 忽略亮色暗色背景 - hsv_base_mask_range_ignore_light = [[[0, 0, 0], [180, 254, 230]]] # 忽略亮色背景 - hsv_base_mask_range_ignore_dark = [[[0, 1, 40], [180, 255, 255]]] # 忽略暗色背景 - rgb_base_mask_range_ignore_light = [[[0, 0, 0], [200, 200, 200]]] # 忽略亮色背景 - rgb_base_mask_range_ignore_dark = [[[20, 20, 20], [255, 255, 255]]] # 忽略暗色背景 +if __name__ == "__main__": + luv_base_mask_range_ignore_light = [[[0, 0, 0], [230, 255, 255]]] # 忽略亮色背景 + luv_base_mask_range_ignore_dark = [[[20, 0, 0], [255, 255, 255]]] # 忽略暗色背景 + luv_base_mask_range_ignore_light_dark = [ + [[20, 0, 0], [230, 255, 255]] + ] # 忽略亮色暗色背景 + hsv_base_mask_range_ignore_light = [[[0, 0, 0], [180, 254, 230]]] # 忽略亮色背景 + hsv_base_mask_range_ignore_dark = [[[0, 1, 40], [180, 255, 255]]] # 忽略暗色背景 + rgb_base_mask_range_ignore_light = [[[0, 0, 0], [200, 200, 200]]] # 忽略亮色背景 + rgb_base_mask_range_ignore_dark = [[[20, 20, 20], [255, 255, 255]]] # 忽略暗色背景 # 自动判断图片的合适 mask_ranges # image = cv2.imread(str(maa_dir / "resource" / "template" / "Roguelike" / "JieGarden" / "JieGarden@Roguelike@StageWindAndRain.png")) @@ -22,35 +30,46 @@ if __name__ == '__main__': # generate_mask_ranges(image, 'rgb', rgb_base_mask_range_ignore_dark) # 在给定的 mask_ranges 下展示一张图 - image = cv2.imread(str(maa_dir / "resource" / "template" / "Roguelike" / "JieGarden" / "JieGarden@Roguelike@StageDreadfulFoe.png")) - mask_ranges = [ - [ - [100, 0, 40], - [140, 220, 255] - ], - [ - [0, 0, 230], - [180, 30, 255] - ] - ] + image = cv2.imread( + str( + maa_dir + / "resource" + / "template" + / "Roguelike" + / "JieGarden" + / "JieGarden@Roguelike@StageDreadfulFoe.png" + ) + ) + mask_ranges = [[[100, 0, 40], [140, 220, 255]], [[0, 0, 230], [180, 30, 255]]] - show_image_mask(image, calc_mask_from_ranges(image, mask_ranges, 'hsv', False), 'hsv') + show_image_mask( + image, calc_mask_from_ranges(image, mask_ranges, "hsv", False), "hsv" + ) # mask_ranges = [[[93, 81, 130], [102, 97, 142]], [[128, 100, 164], [134, 110, 169]], [[95, 85, 145], [105, 95, 155]]] # show_image_mask(image, calc_mask_from_ranges(image, mask_ranges, 'luv', True), 'luv') # 在给定的 mask_ranges 下比较两张图 - image1 = cv2.imread(str(maa_dir / "resource" / "template" / "Roguelike" / "JieGarden" / "JieGarden@Roguelike@StageDreadfulFoe-5.png")) - image2 = cv2.imread(str(maa_dir / "resource" / "template" / "Roguelike" / "JieGarden" / "JieGarden@Roguelike@StageDreadfulFoe.png")) - mask_ranges = [ - [ - [100, 0, 40], - [140, 220, 255] - ], - [ - [0, 0, 230], - [180, 30, 255] - ] - ] + image1 = cv2.imread( + str( + maa_dir + / "resource" + / "template" + / "Roguelike" + / "JieGarden" + / "JieGarden@Roguelike@StageDreadfulFoe-5.png" + ) + ) + image2 = cv2.imread( + str( + maa_dir + / "resource" + / "template" + / "Roguelike" + / "JieGarden" + / "JieGarden@Roguelike@StageDreadfulFoe.png" + ) + ) + mask_ranges = [[[100, 0, 40], [140, 220, 255]], [[0, 0, 230], [180, 30, 255]]] compare_2_image_with_mask_ranges(image1, image2, mask_ranges, "hsv") # compare_2_image_with_mask_ranges(image1, image2, mask_ranges, "hsv", True) diff --git a/tools/MaskRangeTool/utils.py b/tools/MaskRangeTool/mask_utils.py similarity index 63% rename from tools/MaskRangeTool/utils.py rename to tools/MaskRangeTool/mask_utils.py index 2c25b0497f..146d00e8d9 100644 --- a/tools/MaskRangeTool/utils.py +++ b/tools/MaskRangeTool/mask_utils.py @@ -1,14 +1,14 @@ import cv2 -import numpy as np import matplotlib.pyplot as plt +import numpy as np def convert_color(image, color): - if color.lower() == 'luv': + if color.lower() == "luv": return cv2.cvtColor(image, cv2.COLOR_BGR2Luv) - elif color.lower() == 'hsv': + elif color.lower() == "hsv": return cv2.cvtColor(image, cv2.COLOR_BGR2HSV) - elif color.lower() == 'rgb': + elif color.lower() == "rgb": return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) else: raise RuntimeError("Invalid param `color` in function convert_color") @@ -25,7 +25,9 @@ def calc_mask_from_ranges(image, mask_ranges, color=None, mask_close=False): l0, l1, l2 = mask_range[0] u0, u1, u2 = mask_range[1] if mask is not None: - mask = cv2.bitwise_or(mask, cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2))) + mask = cv2.bitwise_or( + mask, cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2)) + ) else: mask = cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2)) @@ -44,46 +46,61 @@ def show_image_mask(image, mask, color, hist_mask=None): # channel ranges CHANNEL_RANGES = { - 'luv': [(0, 255), (0, 255), (0, 255)], - 'hsv': [(0, 179), (0, 255), (0, 255)], - 'rgb': [(0, 255), (0, 255), (0, 255)] + "luv": [(0, 255), (0, 255), (0, 255)], + "hsv": [(0, 179), (0, 255), (0, 255)], + "rgb": [(0, 255), (0, 255), (0, 255)], } channel_ranges = CHANNEL_RANGES[color.lower()] - hist_0 = cv2.calcHist([image_for_hist], [0], hist_mask, [channel_ranges[0][1] - channel_ranges[0][0]], - [channel_ranges[0][0], channel_ranges[0][1] + 1]) - hist_1 = cv2.calcHist([image_for_hist], [1], hist_mask, [channel_ranges[1][1] - channel_ranges[1][0]], - [channel_ranges[1][0], channel_ranges[1][1] + 1]) - hist_2 = cv2.calcHist([image_for_hist], [2], hist_mask, [channel_ranges[2][1] - channel_ranges[2][0]], - [channel_ranges[2][0], channel_ranges[2][1] + 1]) + hist_0 = cv2.calcHist( + [image_for_hist], + [0], + hist_mask, + [channel_ranges[0][1] - channel_ranges[0][0]], + [channel_ranges[0][0], channel_ranges[0][1] + 1], + ) + hist_1 = cv2.calcHist( + [image_for_hist], + [1], + hist_mask, + [channel_ranges[1][1] - channel_ranges[1][0]], + [channel_ranges[1][0], channel_ranges[1][1] + 1], + ) + hist_2 = cv2.calcHist( + [image_for_hist], + [2], + hist_mask, + [channel_ranges[2][1] - channel_ranges[2][0]], + [channel_ranges[2][0], channel_ranges[2][1] + 1], + ) - axs[0, 0].plot(hist_0, color='r') - axs[0, 0].set_title('Channel 0 Histogram') + axs[0, 0].plot(hist_0, color="r") + axs[0, 0].set_title("Channel 0 Histogram") axs[0, 0].set_xlim([channel_ranges[0][0], channel_ranges[0][1]]) - axs[0, 1].plot(hist_1, color='g') - axs[0, 1].set_title('Channel 1 Histogram') + axs[0, 1].plot(hist_1, color="g") + axs[0, 1].set_title("Channel 1 Histogram") axs[0, 1].set_xlim([channel_ranges[1][0], channel_ranges[1][1]]) - axs[0, 2].plot(hist_2, color='b') - axs[0, 2].set_title('Channel 2 Histogram') + axs[0, 2].plot(hist_2, color="b") + axs[0, 2].set_title("Channel 2 Histogram") axs[0, 2].set_xlim([channel_ranges[2][0], channel_ranges[2][1]]) # 原图 axs[1, 0].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) - axs[1, 0].set_title('Original Image') - axs[1, 0].axis('off') + axs[1, 0].set_title("Original Image") + axs[1, 0].axis("off") # 掩码后的图像 axs[1, 1].imshow(cv2.cvtColor(image_with_mask, cv2.COLOR_BGR2RGB)) - axs[1, 1].set_title('Image with Mask') - axs[1, 1].axis('off') + axs[1, 1].set_title("Image with Mask") + axs[1, 1].axis("off") # 显示掩码 - axs[1, 2].imshow(mask, cmap='gray') - axs[1, 2].set_title('Mask') - axs[1, 2].axis('off') + axs[1, 2].imshow(mask, cmap="gray") + axs[1, 2].set_title("Mask") + axs[1, 2].axis("off") plt.tight_layout() plt.show() @@ -123,15 +140,21 @@ def generate_mask_ranges(image, color, base_mask_ranges=None, thresholds=None): break mask_ranges.append([[l0, l1, l2], [u0, u1, u2]]) - mask = cv2.bitwise_or(mask, cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2))) + mask = cv2.bitwise_or( + mask, cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2)) + ) - print(f'Recommend {color.upper()} Mask Range: {mask_ranges}') - show_image_mask(image, calc_mask_from_ranges(image, mask_ranges, color), color, base_mask) + print(f"Recommend {color.upper()} Mask Range: {mask_ranges}") + show_image_mask( + image, calc_mask_from_ranges(image, mask_ranges, color), color, base_mask + ) return mask_ranges -def compare_2_image_with_mask_ranges(image1, image2, mask_ranges, color, mask_close=False): +def compare_2_image_with_mask_ranges( + image1, image2, mask_ranges, color, mask_close=False +): image1_for_mask = convert_color(image1, color) image2_for_mask = convert_color(image2, color) @@ -145,33 +168,33 @@ def compare_2_image_with_mask_ranges(image1, image2, mask_ranges, color, mask_cl # 原图 axs[0, 0].imshow(cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)) - axs[0, 0].set_title('Original Image') - axs[0, 0].axis('off') + axs[0, 0].set_title("Original Image") + axs[0, 0].axis("off") # 掩码后的图像 axs[0, 1].imshow(cv2.cvtColor(image1_with_mask, cv2.COLOR_BGR2RGB)) - axs[0, 1].set_title('Image with Mask') - axs[0, 1].axis('off') + axs[0, 1].set_title("Image with Mask") + axs[0, 1].axis("off") # 显示掩码 - axs[0, 2].imshow(mask1, cmap='gray') - axs[0, 2].set_title('Mask') - axs[0, 2].axis('off') + axs[0, 2].imshow(mask1, cmap="gray") + axs[0, 2].set_title("Mask") + axs[0, 2].axis("off") # 原图 axs[1, 0].imshow(cv2.cvtColor(image2, cv2.COLOR_BGR2RGB)) - axs[1, 0].set_title('Original Image') - axs[1, 0].axis('off') + axs[1, 0].set_title("Original Image") + axs[1, 0].axis("off") # 掩码后的图像 axs[1, 1].imshow(cv2.cvtColor(image2_with_mask, cv2.COLOR_BGR2RGB)) - axs[1, 1].set_title('Image with Mask') - axs[1, 1].axis('off') + axs[1, 1].set_title("Image with Mask") + axs[1, 1].axis("off") # 显示掩码 - axs[1, 2].imshow(mask2, cmap='gray') - axs[1, 2].set_title('Mask') - axs[1, 2].axis('off') + axs[1, 2].imshow(mask2, cmap="gray") + axs[1, 2].set_title("Mask") + axs[1, 2].axis("off") plt.tight_layout() plt.show() diff --git a/tools/OptimizeTemplates/optimize_templates.py b/tools/OptimizeTemplates/optimize_templates.py index e46905f3ec..5c9875a1b5 100644 --- a/tools/OptimizeTemplates/optimize_templates.py +++ b/tools/OptimizeTemplates/optimize_templates.py @@ -1,17 +1,18 @@ -from argparse import ArgumentParser -from tqdm import tqdm +import hashlib import json import os -import struct -import hashlib import pathlib import re +import struct +from argparse import ArgumentParser import numpy as np from PIL import Image +from tqdm import tqdm + def remove_auxiliary_data(input_file, output_file): - with open(input_file, 'rb') as f: + with open(input_file, "rb") as f: data = f.read() output_data = bytearray() @@ -20,41 +21,48 @@ def remove_auxiliary_data(input_file, output_file): # Locate and copy critical chunks start = 8 while start < len(data): - length, chunk_type = struct.unpack('>I4s', data[start:start+8]) + length, chunk_type = struct.unpack(">I4s", data[start : start + 8]) start += 8 - chunk_data = data[start:start+length] + chunk_data = data[start : start + length] start += length - crc = data[start:start+4] + crc = data[start : start + 4] start += 4 - if chunk_type in [b'IHDR', b'PLTE', b'IDAT', b'IEND']: - output_data.extend(struct.pack('>I4s', length, chunk_type)) + if chunk_type in [b"IHDR", b"PLTE", b"IDAT", b"IEND"]: + output_data.extend(struct.pack(">I4s", length, chunk_type)) output_data.extend(chunk_data) output_data.extend(crc) - with open(output_file, 'wb') as f: + with open(output_file, "wb") as f: f.write(output_data) + def get_file_id(file_path: str): file_id = file_path.replace("\\", "/") # resource\\global\\{SERVERNAME}\\resource\\template\\xxx.png-> {SERVERNAME}/xxx m = re.search(r"global/(\w+)/resource/template/([^/]+)\.png", file_id) - if m: return f"{m.group(1)}/{m.group(2)}" + if m: + return f"{m.group(1)}/{m.group(2)}" # resource\\template\\xxx.png-> official/xxx m = re.search(r"template/([^/]+)\.png", file_id) - if m: return f"official/{m.group(1)}" + if m: + return f"official/{m.group(1)}" # resource\\PATH\\TO\\xxx.png-> resource/PATH/TO/xxx m = re.search(r"resource/(.*)\.png", file_id) - if m: return f"resource/{m.group(1)}" + if m: + return f"resource/{m.group(1)}" # docs\\.vuepress\\public\\image\\PATH\\TO\\xxx.png -> docs/PATH/TO/xxx m = re.search(r"docs/.vuepress/public/images/(.*)\.png", file_id) - if m: return f"docs/{m.group(1)}" + if m: + return f"docs/{m.group(1)}" # website\\apps\\web\\PATH\\TO\\xxx.png -> web/PATH/TO/xxx m = re.search(r"website/apps/web/(.*)\.png", file_id) - if m: return f"web/{m.group(1)}" + if m: + return f"web/{m.group(1)}" return None + def check_png_need_update(file_path: str, perfect_pngs: dict, quiet: bool): # convert to absolute path file_path = str(pathlib.Path(file_path).resolve()) @@ -72,14 +80,17 @@ def check_png_need_update(file_path: str, perfect_pngs: dict, quiet: bool): data = f.read() sha256 = hashlib.sha256(data).hexdigest() if sha256 == perfect_pngs[file_id]: - if not quiet: print("skip", file_path) + if not quiet: + print("skip", file_path) return False return True + def update_png_with_optipng(file_path: str, perfect_pngs: dict, quiet: bool): if check_png_need_update(file_path, perfect_pngs, quiet): - if not quiet: print("updating", file_path) + if not quiet: + print("updating", file_path) else: return False @@ -90,14 +101,16 @@ def update_png_with_optipng(file_path: str, perfect_pngs: dict, quiet: bool): input_file = output_file = file_path remove_auxiliary_data(input_file, output_file) if quiet: - os.system(f"optipng -quiet -o7 -zm1-9 -fix \"{output_file}\"") + os.system(f'optipng -quiet -o7 -zm1-9 -fix "{output_file}"') else: - os.system(f"optipng -o7 -zm1-9 -fix \"{output_file}\"") + os.system(f'optipng -o7 -zm1-9 -fix "{output_file}"') sz_after = os.stat(file_path).st_size if not quiet: - print(f"before: {sz_before} Bytes, after: {sz_after} Bytes, diff: {sz_before - sz_after} Bytes") + print( + f"before: {sz_before} Bytes, after: {sz_after} Bytes, diff: {sz_before - sz_after} Bytes" + ) # update file sha256 with open(file_path, "rb") as f: @@ -105,13 +118,16 @@ def update_png_with_optipng(file_path: str, perfect_pngs: dict, quiet: bool): sha256 = hashlib.sha256(data).hexdigest() perfect_pngs.update({file_id: sha256}) - if not quiet: print("updated", file_path) + if not quiet: + print("updated", file_path) update_perfect_png_dict(perfect_pngs) return sz_before - sz_after + def update_png_with_oxipng(file_path: str, perfect_pngs: dict, quiet: bool): if check_png_need_update(file_path, perfect_pngs, quiet): - if not quiet: print("updating", file_path) + if not quiet: + print("updating", file_path) else: return False @@ -119,19 +135,21 @@ def update_png_with_oxipng(file_path: str, perfect_pngs: dict, quiet: bool): file_id = get_file_id(file_path) sz_before = os.stat(file_path).st_size - img_before = np.array(Image.open(file_path).convert('L')) + img_before = np.array(Image.open(file_path).convert("L")) if quiet: - os.system(f"oxipng -o max --fast -Z -s -q \"{file_path}\"") - os.system(f"oxipng -o 2 -s -q \"{file_path}\"") + os.system(f'oxipng -o max --fast -Z -s -q "{file_path}"') + os.system(f'oxipng -o 2 -s -q "{file_path}"') else: - os.system(f"oxipng -o max --fast -Z -s \"{file_path}\"") - os.system(f"oxipng -o 2 -s \"{file_path}\"") + os.system(f'oxipng -o max --fast -Z -s "{file_path}"') + os.system(f'oxipng -o 2 -s "{file_path}"') sz_after = os.stat(file_path).st_size if not quiet: - print(f"before: {sz_before} Bytes, after: {sz_after} Bytes, diff: {sz_before - sz_after} Bytes") + print( + f"before: {sz_before} Bytes, after: {sz_after} Bytes, diff: {sz_before - sz_after} Bytes" + ) # update file sha256 with open(file_path, "rb") as f: @@ -139,27 +157,40 @@ def update_png_with_oxipng(file_path: str, perfect_pngs: dict, quiet: bool): sha256 = hashlib.sha256(data).hexdigest() perfect_pngs.update({file_id: sha256}) - img_after = np.array(Image.open(file_path).convert('L')) + img_after = np.array(Image.open(file_path).convert("L")) if not (img_before == img_after).all(): return -1 - if not quiet: print("updated", file_path) + if not quiet: + print("updated", file_path) update_perfect_png_dict(perfect_pngs) return sz_before - sz_after + cur_dir = pathlib.Path(__file__).parent.resolve() perfect_pngs_path = str(cur_dir / "optimize_templates.json") + + def update_perfect_png_dict(perfect_pngs: dict): with open(perfect_pngs_path, "w") as f: json.dump(perfect_pngs, f, indent=4) + def ArgParser(): parser = ArgumentParser() - parser.add_argument("-p", "--path", dest="path", nargs="*", help="the paths of png files or folders", default=[]) + parser.add_argument( + "-p", + "--path", + dest="path", + nargs="*", + help="the paths of png files or folders", + default=[], + ) parser.add_argument("-q", "--quiet", dest="quiet", action="store_true") return parser -if __name__ == '__main__': + +if __name__ == "__main__": args = ArgParser().parse_args() paths = args.path quiet = args.quiet @@ -193,13 +224,14 @@ if __name__ == '__main__': file = os.path.join(root, f) if check_png_need_update(file, perfect_pngs, quiet): files.append(file) - tqdm_total += os.stat(file).st_size ** 2 // 2 ** 20 + tqdm_total += os.stat(file).st_size ** 2 // 2**20 elif pathlib.Path(path).is_file(): files.append(path) - tqdm_total += os.stat(path).st_size ** 2 // 2 ** 20 + tqdm_total += os.stat(path).st_size ** 2 // 2**20 total_diff_sz = 0 - if quiet: t = tqdm(files, total=tqdm_total) + if quiet: + t = tqdm(files, total=tqdm_total) for i, file in enumerate(files): cur_file_sz = os.stat(file).st_size diff_sz = update_png_with_oxipng(file, perfect_pngs, quiet) @@ -218,8 +250,12 @@ if __name__ == '__main__': total_diff_sz_str = f"{(total_diff_sz / 1048576):.2f} MiB" if quiet: - t.update(cur_file_sz ** 2 // 2 ** 20) - t.set_postfix(file_counts=f"{i+1}/{len(files)}", reduced_size=total_diff_sz_str) + t.update(cur_file_sz**2 // 2**20) + t.set_postfix( + file_counts=f"{i+1}/{len(files)}", reduced_size=total_diff_sz_str + ) t.refresh() else: - print(f"file counts: {i+1}/{len(files)}, reduced pngs size: {total_diff_sz_str}") + print( + f"file counts: {i+1}/{len(files)}, reduced pngs size: {total_diff_sz_str}" + ) diff --git a/tools/OverseasClients/FindMissingJsonTranslate.py b/tools/OverseasClients/FindMissingJsonTranslate.py index 62606489b3..bfba093765 100644 --- a/tools/OverseasClients/FindMissingJsonTranslate.py +++ b/tools/OverseasClients/FindMissingJsonTranslate.py @@ -1,7 +1,7 @@ import json import os -import sys import re +import sys # NOTE # You may customize here @@ -14,7 +14,6 @@ regex_ignore_list = [ "DT-7@SideStoryStage", "DT-6@SideStoryStage", "DT-3@SideStoryStage", - # CUSTOM "AccountManager", "Logout", @@ -31,21 +30,16 @@ regex_ignore_list = [ "StageDrops-StageCF-FoodBonusFlag", "StageDrops-Stage12-TripleFlag", "Tales@RA@PIS-ClickTool", - # FUTURE MODES/EVENTS - "StartExploreWithSeed" + "StartExploreWithSeed", ] -server_list = [ - "YoStarJP", - "YoStarEN", - "YoStarKR", - "txwy" -] +server_list = ["YoStarJP", "YoStarEN", "YoStarKR", "txwy"] cur_dir = os.path.dirname(os.path.abspath(__file__)) proj_dir = os.path.join(cur_dir, "../../") + def find_missing_translations(server_name): output_file = "missing_translate-" + server_name + ".txt" @@ -57,16 +51,17 @@ def find_missing_translations(server_name): json_name = "tasks.json" zh_json_file = os.path.join(proj_dir, "resource/", json_name) - gl_json_file = os.path.join(proj_dir, "resource/global/", - server_name, "resource/", json_name) + gl_json_file = os.path.join( + proj_dir, "resource/global/", server_name, "resource/", json_name + ) # For test purpose # gl_json_file = os.path.join(cur_dir, "test.json") - with open(zh_json_file, 'r', encoding='utf-8') as zh_fh: + with open(zh_json_file, "r", encoding="utf-8") as zh_fh: zh_json: dict = json.load(zh_fh) - with open(gl_json_file, 'r', encoding='utf-8') as gl_fh: + with open(gl_json_file, "r", encoding="utf-8") as gl_fh: gl_json: dict = json.load(gl_fh) # def getBaseTask(task: dict) -> dict: @@ -94,15 +89,16 @@ def find_missing_translations(server_name): if all(map(str.isascii, value["text"])): continue - res_keys.append(key + ': ' + ', '.join(value["text"])) + res_keys.append(key + ": " + ", ".join(value["text"])) print(key, value["text"]) - with open(output_file, 'w', encoding='utf-8') as f: - f.write('\n'.join(res_keys)) + with open(output_file, "w", encoding="utf-8") as f: + f.write("\n".join(res_keys)) print("Missing translations written to", output_file) + def main(): # Get the server name from argument # try: @@ -127,5 +123,6 @@ def main(): for server_name in server_names: find_missing_translations(server_name) + if __name__ == "__main__": main() diff --git a/tools/OverseasClients/FindMissingTemplates.py b/tools/OverseasClients/FindMissingTemplates.py index 858fb1f4c3..8f3bdb1baf 100644 --- a/tools/OverseasClients/FindMissingTemplates.py +++ b/tools/OverseasClients/FindMissingTemplates.py @@ -21,9 +21,9 @@ import os -import sys -import shutil import re +import shutil +import sys # NOTE # Put the file names of text-less images (so that global servers use the same @@ -40,36 +40,37 @@ regex_ignore_list = [ # UNRELEASED I.S. ] -server_list = [ - "YoStarJP", - "YoStarEN", - "YoStarKR", - "txwy" -] +server_list = ["YoStarJP", "YoStarEN", "YoStarKR", "txwy"] cur_dir = os.path.dirname(os.path.abspath(__file__)) proj_dir = os.path.join(cur_dir, "../../") + def find_missing_templates(server_name): zh_dir = os.path.join(proj_dir, "resource/template/") - gl_dir = os.path.join(proj_dir, "resource/global/", - server_name, "resource/template/") + gl_dir = os.path.join( + proj_dir, "resource/global/", server_name, "resource/template/" + ) - zh_files = [f for f in os.listdir( - zh_dir) if os.path.isfile(os.path.join(zh_dir, f))] - gl_files = [f for f in os.listdir( - gl_dir) if os.path.isfile(os.path.join(gl_dir, f))] + zh_files = [ + f for f in os.listdir(zh_dir) if os.path.isfile(os.path.join(zh_dir, f)) + ] + gl_files = [ + f for f in os.listdir(gl_dir) if os.path.isfile(os.path.join(gl_dir, f)) + ] with open(os.path.join(cur_dir, ignore_list_file_name)) as f: - ignore_files = [line.rstrip('\n') for line in f] + ignore_files = [line.rstrip("\n") for line in f] # ZH server pics not found in global server nor ignored will be filtered here - diff_files = [f for f in zh_files if - not any(map(lambda x: re.search(x, f), regex_ignore_list)) and - f not in gl_files and - f not in ignore_files - ] + diff_files = [ + f + for f in zh_files + if not any(map(lambda x: re.search(x, f), regex_ignore_list)) + and f not in gl_files + and f not in ignore_files + ] # These pictures will be copied to the missing_templates folder for reference. # Contributors of global servers may screenshot the corresponding files. @@ -83,8 +84,12 @@ def find_missing_templates(server_name): # print(f) shutil.copyfile(os.path.join(zh_dir, f), os.path.join(out_dir, f)) - print("Pictures not included in", server_name, - "server resources is copied to missing_templates/" + server_name) + print( + "Pictures not included in", + server_name, + "server resources is copied to missing_templates/" + server_name, + ) + def main(): # Get the server name from argument @@ -110,5 +115,6 @@ def main(): for server_name in server_names: find_missing_templates(server_name) + if __name__ == "__main__": main() diff --git a/tools/OverseasClients/SortJsonByZHServerOrder.py b/tools/OverseasClients/SortJsonByZHServerOrder.py index 5187516664..ec0a47c274 100644 --- a/tools/OverseasClients/SortJsonByZHServerOrder.py +++ b/tools/OverseasClients/SortJsonByZHServerOrder.py @@ -18,31 +18,10 @@ import sys from collections import OrderedDict server_list = { - "YoStarJP": [ - "yostarjp", - "jp", - "日", - "日服" - ], - "YoStarEN": [ - "yostaren", - "en", - "美", - "美服", - "國際", - "國際服" - ], - "YoStarKR": [ - "yostarkr", - "kr", - "韓", - "韓服" - ], - "txwy": [ - "txwy" - "繁中", - "繁中服" - ] + "YoStarJP": ["yostarjp", "jp", "日", "日服"], + "YoStarEN": ["yostaren", "en", "美", "美服", "國際", "國際服"], + "YoStarKR": ["yostarkr", "kr", "韓", "韓服"], + "txwy": ["txwy", "繁中", "繁中服"], } # Get the server name from argument @@ -50,17 +29,25 @@ try: # server_name = YoStarJP server_name = None for listed_server in server_list: - server_name = listed_server if (not server_name) and sys.argv[1].casefold() in server_list[listed_server] else server_name + server_name = ( + listed_server + if (not server_name) + and sys.argv[1].casefold() in server_list[listed_server] + else server_name + ) if server_name not in server_list: raise except Exception: server_name = None - while (not server_name): - print("Enter one and only one server name:", - ", ".join(server_list)) + while not server_name: + print("Enter one and only one server name:", ", ".join(server_list)) t = input() for listed_server in server_list: - server_name = listed_server if (not server_name) and t.casefold() in server_list[listed_server] else server_name + server_name = ( + listed_server + if (not server_name) and t.casefold() in server_list[listed_server] + else server_name + ) cur_dir = os.path.dirname(os.path.abspath(__file__)) proj_dir = os.path.join(cur_dir, "../../") @@ -74,16 +61,17 @@ except IndexError: json_name = "tasks.json" zh_json_file = os.path.join(proj_dir, "resource", json_name) -gl_json_file = os.path.join(proj_dir, "resource", "global", - server_name, "resource", json_name) +gl_json_file = os.path.join( + proj_dir, "resource", "global", server_name, "resource", json_name +) # For test purpose # gl_json_file = os.path.join(cur_dir, "test.json") -with open(zh_json_file, 'r', encoding='utf-8') as zh_fh: +with open(zh_json_file, "r", encoding="utf-8") as zh_fh: zh_json = json.load(zh_fh) -with open(gl_json_file, 'r', encoding='utf-8') as gl_fh: +with open(gl_json_file, "r", encoding="utf-8") as gl_fh: gl_json = json.load(gl_fh) # Sort the global json object by the order of the ZH one @@ -91,11 +79,14 @@ with open(gl_json_file, 'r', encoding='utf-8') as gl_fh: LAST_POSITIONS = 1e10 key_order = {k: v for v, k in enumerate(zh_json)} gl_json_new = OrderedDict( - sorted(gl_json.items(), key=lambda i: key_order.get(i[0], LAST_POSITIONS))) + sorted(gl_json.items(), key=lambda i: key_order.get(i[0], LAST_POSITIONS)) +) -with open(gl_json_file, 'wb') as gl_fh: +with open(gl_json_file, "wb") as gl_fh: t = json.dumps(gl_json_new, indent=4, ensure_ascii=False) gl_fh.write(bytes(t, "utf-8")) - print("successfully sorted", - os.path.join("resource", "global", server_name, "resource", json_name), - "by the order in ZH json file") + print( + "successfully sorted", + os.path.join("resource", "global", server_name, "resource", json_name), + "by the order in ZH json file", + ) diff --git a/tools/RoguelikeOperSearch/RoguelikeOperSearch.py b/tools/RoguelikeOperSearch/RoguelikeOperSearch.py index 9aa21d0c5b..74c85382f1 100644 --- a/tools/RoguelikeOperSearch/RoguelikeOperSearch.py +++ b/tools/RoguelikeOperSearch/RoguelikeOperSearch.py @@ -1,5 +1,5 @@ -import os import json +import os cur_dir = os.path.dirname(os.path.abspath(__file__)) proj_dir = os.path.join(cur_dir, "../../") @@ -9,37 +9,40 @@ theme_paths = { "Phantom": os.path.join(proj_dir, "resource/roguelike/Phantom/recruitment.json"), "Mizuki": os.path.join(proj_dir, "resource/roguelike/Mizuki/recruitment.json"), "Sami": os.path.join(proj_dir, "resource/roguelike/Sami/recruitment.json"), - "Sarkaz": os.path.join(proj_dir, "resource/roguelike/Sarkaz/recruitment.json") + "Sarkaz": os.path.join(proj_dir, "resource/roguelike/Sarkaz/recruitment.json"), } + def read_battle_data_names(): - with open(battle_data_path, 'r', encoding='utf-8') as f: + with open(battle_data_path, "r", encoding="utf-8") as f: data = json.load(f) names = [] for key, value in data.get("chars", {}).items(): if key.startswith("char_"): - if value.get("rarity") and value.get("rarity") >=3: + if value.get("rarity") and value.get("rarity") >= 3: name = value.get("name") if name: names.append(name) return names + def check_recruitment_files(names): missing_oper = {} for theme, path in theme_paths.items(): missing_oper[theme] = [] - with open(path, 'r', encoding='utf-8') as f: + with open(path, "r", encoding="utf-8") as f: content = f.read() for name in names: if content.find(f'"{name}"') == -1: missing_oper[theme].append(name) # 输出到missing_oper.txt - with open(os.path.join(cur_dir, 'missing_oper.txt'), 'w', encoding='utf-8') as f: + with open(os.path.join(cur_dir, "missing_oper.txt"), "w", encoding="utf-8") as f: for theme, missing_names in missing_oper.items(): if missing_names: f.write(f"{theme}: {' , '.join(missing_names)}\n") + if __name__ == "__main__": names = read_battle_data_names() check_recruitment_files(names) diff --git a/tools/RoguelikeRecruitmentTool/main.py b/tools/RoguelikeRecruitmentTool/main.py index 554321257d..3ba0248a5d 100644 --- a/tools/RoguelikeRecruitmentTool/main.py +++ b/tools/RoguelikeRecruitmentTool/main.py @@ -2,7 +2,6 @@ from pathlib import Path from roguelike_recruitment_tool import RecruitmentTool - if __name__ == "__main__": resource_path = Path(__file__).resolve().parent.parent.parent / "resource" diff --git a/tools/RoguelikeRecruitmentTool/roguelike/config/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike/config/__init__.py index cc1d99f939..1d096b5101 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike/config/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike/config/__init__.py @@ -1,6 +1,3 @@ from .main import Theme - -__all__ = [ - "Theme" -] +__all__ = ["Theme"] diff --git a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/__init__.py index 4ed218877e..abc98e949e 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/__init__.py @@ -1,17 +1,16 @@ -from .main import ( - RecruitPriorityOffset, - CollectionPriorityOffset, - Oper, - Group, - TeamCompleteCondition, - Configuration, - new_recruit_priority_offset, - new_collection_priority_offset, - new_oper, - new_group -) from .export import export_config - +from .main import ( + CollectionPriorityOffset, + Configuration, + Group, + Oper, + RecruitPriorityOffset, + TeamCompleteCondition, + new_collection_priority_offset, + new_group, + new_oper, + new_recruit_priority_offset, +) __all__ = [ "RecruitPriorityOffset", @@ -24,5 +23,5 @@ __all__ = [ "new_collection_priority_offset", "new_oper", "new_group", - "export_config" + "export_config", ] diff --git a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/export.py b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/export.py index 2ab6438fc7..c3dc39e6a2 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/export.py +++ b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/export.py @@ -1,9 +1,9 @@ -from pandas import DataFrame from pathlib import Path +from pandas import DataFrame from roguelike.config import Theme -from .main import RecruitPriorityOffset, Oper, Configuration +from .main import Configuration, Oper, RecruitPriorityOffset # contributed by Lancarus @@ -23,7 +23,9 @@ def export_config(output_path: Path, theme: Theme, config: Configuration) -> Non for offset_index in range(len(offset_list)): offset = offset_list[offset_index] for offset_field in offset.model_fields: - oper_dict[f"{offset_field}_{offset_index + 1}"] = getattr(offset, offset_field) + oper_dict[f"{offset_field}_{offset_index + 1}"] = getattr( + offset, offset_field + ) else: oper_dict[oper_field] = getattr(oper, oper_field) table.append(oper_dict) diff --git a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/main.py b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/main.py index 97127a989a..0fdf4242da 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/main.py +++ b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/main.py @@ -4,6 +4,8 @@ from contextvars import ContextVar from copy import deepcopy from os import system from pathlib import Path +from typing import Any, ClassVar, ForwardRef, Iterator + from pydantic import ( BaseModel, Field, @@ -14,12 +16,10 @@ from pydantic import ( ValidationInfo, conlist, model_serializer, - model_validator + model_validator, ) -from typing import Any, ClassVar, ForwardRef, Iterator -from typing_extensions import Annotated, Self - from roguelike.config import Theme +from typing_extensions import Annotated, Self # ================================================================================ # Context @@ -42,7 +42,9 @@ def context(value: dict[str, Any]) -> Iterator[None]: # StrictStr is different from pydantic.types.StrictStr by "strip_whitespace=True" StrictStr = Annotated[str, StringConstraints(strip_whitespace=True, strict=True)] -StrictNonEmptyStr = Annotated[str, StringConstraints(strip_whitespace=True, strict=True, min_length=1)] +StrictNonEmptyStr = Annotated[ + str, StringConstraints(strip_whitespace=True, strict=True, min_length=1) +] # ================================================================================ @@ -88,26 +90,49 @@ class Oper(BaseModel, extra="forbid"): name: Annotated[StrictNonEmptyStr, Field(description="干员代号")] doc: StrictStr = "" skill: Annotated[StrictInt, Field(description="技能")] = 0 - skill_usage: Annotated[StrictInt, Field(ge=0, le=3, validate_default=True), Field(description="技能使用模式")] = 1 + skill_usage: Annotated[ + StrictInt, + Field(ge=0, le=3, validate_default=True), + Field(description="技能使用模式"), + ] = 1 skill_times: Annotated[StrictInt, Field(description="技能使用次数")] = 1 alternate_skill: Annotated[StrictInt, Field(description="备选技能")] = 0 alternate_skill_usage: Annotated[ - StrictInt, Field(ge=0, le=3, validate_default=True), Field(description="备选技能使用技能")] = 1 - alternate_skill_times: Annotated[StrictInt, Field(description="备选技能使用模式")] = 1 + StrictInt, + Field(ge=0, le=3, validate_default=True), + Field(description="备选技能使用技能"), + ] = 1 + alternate_skill_times: Annotated[ + StrictInt, Field(description="备选技能使用模式") + ] = 1 is_key: Annotated[StrictBool, Field(description="是否为关键干员")] = False is_start: Annotated[StrictBool, Field(description="是否为开局干员")] = False is_alternate: StrictBool = False - auto_retreat: Annotated[StrictInt, Field(description="部署后自动撤退间隔(秒)")] = 0 - recruit_priority: Annotated[StrictInt, Field( - description="招募优先级")] = 0 # Annotated[StrictInt, Field(ge=0, le=1000, validate_default=True)] - promote_priority: Annotated[StrictInt, Field( - description="进阶优先级")] = 0 # Annotated[StrictInt, Field(ge=0, le=1000, validate_default=True)] - recruit_priority_when_team_full: StrictInt | None = None # Annotated[StrictInt, Field(ge=0, le=1000)] - promote_priority_when_team_full: StrictInt | None = None # Annotated[StrictInt, Field(ge=0, le=1000)] + auto_retreat: Annotated[ + StrictInt, Field(description="部署后自动撤退间隔(秒)") + ] = 0 + recruit_priority: Annotated[StrictInt, Field(description="招募优先级")] = ( + 0 # Annotated[StrictInt, Field(ge=0, le=1000, validate_default=True)] + ) + promote_priority: Annotated[StrictInt, Field(description="进阶优先级")] = ( + 0 # Annotated[StrictInt, Field(ge=0, le=1000, validate_default=True)] + ) + recruit_priority_when_team_full: StrictInt | None = ( + None # Annotated[StrictInt, Field(ge=0, le=1000)] + ) + promote_priority_when_team_full: StrictInt | None = ( + None # Annotated[StrictInt, Field(ge=0, le=1000)] + ) recruit_priority_offsets: conlist( - item_type=Annotated[RecruitPriorityOffset, Field(strict=True, validate_default=True)]) = list() + item_type=Annotated[ + RecruitPriorityOffset, Field(strict=True, validate_default=True) + ] + ) = list() collection_priority_offsets: conlist( - item_type=Annotated[CollectionPriorityOffset, Field(strict=True, validate_default=True)]) = list() + item_type=Annotated[ + CollectionPriorityOffset, Field(strict=True, validate_default=True) + ] + ) = list() _inherited_attributes: ClassVar[set[str]] = { "skill", @@ -121,7 +146,7 @@ class Oper(BaseModel, extra="forbid"): "is_alternate", "auto_retreat", "recruit_priority", - "promote_priority" + "promote_priority", } def __init__(self, /, **data: Any) -> None: @@ -132,11 +157,16 @@ class Oper(BaseModel, extra="forbid"): if key not in data and key in cache: data[key] = cache[key] if "recruit_priority_when_team_full" not in data: - data["recruit_priority_when_team_full"] = data.get("recruit_priority", 0) - 100 + data["recruit_priority_when_team_full"] = ( + data.get("recruit_priority", 0) - 100 + ) if "promote_priority_when_team_full" not in data: - data["promote_priority_when_team_full"] = data.get("promote_priority", 0) + 300 - data["recruit_priority_offsets"] = (cache.get("recruit_priority_offsets", list()) - + data.get("recruit_priority_offsets", list())) + data["promote_priority_when_team_full"] = ( + data.get("promote_priority", 0) + 300 + ) + data["recruit_priority_offsets"] = cache.get( + "recruit_priority_offsets", list() + ) + data.get("recruit_priority_offsets", list()) if oper_name: oper_info_cache[oper_name] = deepcopy(data) super().__init__(**data) @@ -166,7 +196,9 @@ class Oper(BaseModel, extra="forbid"): setattr(tmp, key, Oper.model_fields[key].get_default()) cache_len: int = len(getattr(cache, "recruit_priority_offsets")) assert len(tmp.recruit_priority_offsets) >= cache_len - assert tmp.recruit_priority_offsets[: cache_len] == getattr(cache, "recruit_priority_offsets") + assert tmp.recruit_priority_offsets[:cache_len] == getattr( + cache, "recruit_priority_offsets" + ) tmp.recruit_priority_offsets = tmp.recruit_priority_offsets[cache_len:] # ———————————————————————————————————————————————————————————————— oper_info_cache[self.name] = deepcopy(self) @@ -181,7 +213,9 @@ class Oper(BaseModel, extra="forbid"): @classmethod def json2oper(cls, json_str: str) -> OperClass: with context({"oper_info_cache": dict()}): - config = cls.model_validate_json(json_str, context={"skip_validation": True}) + config = cls.model_validate_json( + json_str, context={"skip_validation": True} + ) return config @classmethod @@ -238,7 +272,9 @@ ConfigurationClass = ForwardRef("Configuration") class Configuration(BaseModel, extra="forbid"): theme: Theme priority: conlist(item_type=Annotated[Group, Strict()], min_length=1) - team_complete_condition: conlist(item_type=Annotated[TeamCompleteCondition, Strict()]) + team_complete_condition: conlist( + item_type=Annotated[TeamCompleteCondition, Strict()] + ) @model_validator(mode="after") def sanity_check(self, info: ValidationInfo) -> Self: @@ -259,19 +295,23 @@ class Configuration(BaseModel, extra="forbid"): if set(offset.groups) - group_name_set: raise AssertionError( f"unknown group names {set(offset.groups) - group_name_set} " - f"in recruit priority offset for operator {oper.name} in group {group.name}") + f"in recruit priority offset for operator {oper.name} in group {group.name}" + ) # ———————————————————————————————————————————————————————————————— for item in self.team_complete_condition: if set(item.groups) - group_name_set: raise AssertionError( - f"unknown group names {set(item.groups) - group_name_set} in team_complete_condition") + f"unknown group names {set(item.groups) - group_name_set} in team_complete_condition" + ) # ———————————————————————————————————————————————————————————————— return self @classmethod def json2config(cls, json_str: str) -> ConfigurationClass: with context({"oper_info_cache": dict()}): - config = cls.model_validate_json(json_str, context={"skip_validation": True}) + config = cls.model_validate_json( + json_str, context={"skip_validation": True} + ) return config @classmethod @@ -284,11 +324,15 @@ class Configuration(BaseModel, extra="forbid"): # ================================================================================ # new_oper & new_group # ================================================================================ -def new_recruit_priority_offset(operator_name: str = "unnamed operator") -> RecruitPriorityOffset: +def new_recruit_priority_offset( + operator_name: str = "unnamed operator", +) -> RecruitPriorityOffset: return RecruitPriorityOffset(groups=[operator_name], offset=100) -def new_collection_priority_offset(collection_name: str = "unnamed collectible") -> CollectionPriorityOffset: +def new_collection_priority_offset( + collection_name: str = "unnamed collectible", +) -> CollectionPriorityOffset: return CollectionPriorityOffset(collection=collection_name, offset=100) diff --git a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/validation.py b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/validation.py index 87fab9bb86..6bb422c8ca 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike/recruitment/validation.py +++ b/tools/RoguelikeRecruitmentTool/roguelike/recruitment/validation.py @@ -1,8 +1,8 @@ from .main import ( - RecruitPriorityOffset, CollectionPriorityOffset, - Oper, + Configuration, Group, + Oper, + RecruitPriorityOffset, TeamCompleteCondition, - Configuration ) diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/__init__.py index 99603afe99..28532d9e4b 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/__init__.py @@ -1,5 +1,3 @@ from .main import RecruitmentTool -__all__ = [ - "RecruitmentTool" -] +__all__ = ["RecruitmentTool"] diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/common/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/common/__init__.py index e51b0a9210..5d332f0a4f 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/common/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/common/__init__.py @@ -12,34 +12,63 @@ class RecruitmentItemDataRole(IntEnum): DocRole = RecruitmentItemDataRole.DocRole DescriptionRole = RecruitmentItemDataRole.DescriptionRole -str_bool_dict = {"True": True, "False": False, - "true": True, "false": False, - "T": True, "F": False, - "t": True, "f": False, - "1": True, "0": False} +str_bool_dict = { + "True": True, + "False": False, + "true": True, + "false": False, + "T": True, + "F": False, + "t": True, + "f": False, + "1": True, + "0": False, +} def parse_field(value: str, field_type: type) -> Any: print(get_args(field_type)) - if field_type is str or get_origin(field_type) is Annotated and get_args(field_type)[0] is str: + if ( + field_type is str + or get_origin(field_type) is Annotated + and get_args(field_type)[0] is str + ): field_value = value - elif field_type is int or get_origin(field_type) is Annotated and get_args(field_type)[0] is int: + elif ( + field_type is int + or get_origin(field_type) is Annotated + and get_args(field_type)[0] is int + ): try: field_value = int(value) except ValueError: field_value = None - elif field_type is bool or get_origin(field_type) is Annotated and get_args(field_type)[0] is bool: + elif ( + field_type is bool + or get_origin(field_type) is Annotated + and get_args(field_type)[0] is bool + ): global str_bool_dict if value in str_bool_dict: field_value = str_bool_dict[value] else: field_value = None - elif field_type is list or field_type is List or get_origin(field_type) is Annotated and ( - get_args(field_type)[0] is list or get_args(field_type)[0] is List or - get_origin(get_args(field_type)[0]) is list or get_origin(get_args(field_type)[0]) is List): + elif ( + field_type is list + or field_type is List + or get_origin(field_type) is Annotated + and ( + get_args(field_type)[0] is list + or get_args(field_type)[0] is List + or get_origin(get_args(field_type)[0]) is list + or get_origin(get_args(field_type)[0]) is List + ) + ): try: field_value = eval(value) - if not isinstance(field_value, List) and all(map(lambda x: isinstance(x, str), field_value)): + if not isinstance(field_value, List) and all( + map(lambda x: isinstance(x, str), field_value) + ): field_value = None except SyntaxError: field_value = None @@ -49,8 +78,4 @@ def parse_field(value: str, field_type: type) -> Any: return field_value -__all__ = [ - "DocRole", - "DescriptionRole", - "parse_field" -] +__all__ = ["DocRole", "DescriptionRole", "parse_field"] diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/delegates/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/delegates/__init__.py index 063203b6ff..df6745b644 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/delegates/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/delegates/__init__.py @@ -1,6 +1,3 @@ from .editable_delegate import EditableDelegate - -__all__ = [ - "EditableDelegate" -] +__all__ = ["EditableDelegate"] diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/__init__.py index f95343ad7a..6dd559ff5c 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/__init__.py @@ -1,6 +1,3 @@ from .group_edit_dialog import GroupEditDialog - -__all__ = [ - "GroupEditDialog" -] +__all__ = ["GroupEditDialog"] diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/group_edit_dialog.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/group_edit_dialog.py index f7e259a480..4e8bb37877 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/group_edit_dialog.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/dialogs/group_edit_dialog.py @@ -1,7 +1,6 @@ from typing import Optional from PyQt5.QtWidgets import QDialog, QFormLayout, QLineEdit, QPushButton, QWidget - from roguelike.recruitment import Group diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main.py index 582d0d9d01..e50b56dc31 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main.py @@ -1,9 +1,9 @@ from pathlib import Path from PyQt5.QtWidgets import QApplication - from roguelike.config import Theme from roguelike.recruitment import Configuration + from .main_window import MainWindow @@ -18,7 +18,7 @@ class RecruitmentTool(QApplication): self.main_window.set_style = lambda style_name: ( self.setStyle(style_name), self.setPalette(self.style().standardPalette()), - [widget.update() for widget in self.allWidgets()] + [widget.update() for widget in self.allWidgets()], ) self.main_window.version_label.setText(f"Version: {RecruitmentTool.VERSION}") diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main_window.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main_window.py index 0bdcc22372..7d04ef85b4 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main_window.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/main_window.py @@ -1,24 +1,47 @@ from os import system from pathlib import Path -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import (QCheckBox, QComboBox, QDesktopWidget, QFileDialog, QHBoxLayout, QLabel, QLineEdit, - QMainWindow, QMessageBox, QPlainTextEdit, QPushButton, QSizePolicy, QStyleFactory, - QTabWidget, QVBoxLayout, QWidget) - from pydantic import ValidationError - +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import ( + QCheckBox, + QComboBox, + QDesktopWidget, + QFileDialog, + QHBoxLayout, + QLabel, + QLineEdit, + QMainWindow, + QMessageBox, + QPlainTextEdit, + QPushButton, + QSizePolicy, + QStyleFactory, + QTabWidget, + QVBoxLayout, + QWidget, +) from roguelike.config import Theme from roguelike.recruitment import Configuration, export_config from .models import VisualisationModel -from .views import GroupListView, OffsetATableView, OffsetBTableView, OperListView, TabBar, TableView +from .views import ( + GroupListView, + OffsetATableView, + OffsetBTableView, + OperListView, + TabBar, + TableView, +) class MainWindow(QMainWindow): - def __init__(self, configurations: dict[Theme, Configuration], - parent: QWidget = None, - flags: Qt.WindowFlags = Qt.WindowFlags()): + def __init__( + self, + configurations: dict[Theme, Configuration], + parent: QWidget = None, + flags: Qt.WindowFlags = Qt.WindowFlags(), + ): super().__init__(parent, flags) self.configurations: list[Configuration] = configurations @@ -70,7 +93,9 @@ class MainWindow(QMainWindow): self.group_list_view = GroupListView(self.visualisation_widget) self.group_list_view.setModel(self.visualisation_model.group_list_model) - self.group_list_view.selectionModel().selectionChanged.connect(self.visualisation_model.on_group_selection) + self.group_list_view.selectionModel().selectionChanged.connect( + self.visualisation_model.on_group_selection + ) self.group_list_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) tmp_layout.addWidget(self.group_list_view) @@ -91,7 +116,9 @@ class MainWindow(QMainWindow): self.oper_list_view = OperListView(self.visualisation_widget) self.oper_list_view.setModel(self.visualisation_model.oper_list_model) - self.oper_list_view.selectionModel().selectionChanged.connect(self.visualisation_model.on_oper_selection) + self.oper_list_view.selectionModel().selectionChanged.connect( + self.visualisation_model.on_oper_selection + ) self.oper_list_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) tmp_layout.addWidget(self.oper_list_view) @@ -144,8 +171,12 @@ class MainWindow(QMainWindow): self.style_combo_box = QComboBox(self.control_widget) for style_name in QStyleFactory.keys(): self.style_combo_box.addItem(style_name, style_name) - self.style_combo_box.setCurrentIndex(QStyleFactory.keys().index(self.style().objectName())) - self.style_combo_box.currentIndexChanged.connect(lambda: self.set_style(self.style_combo_box.currentData())) + self.style_combo_box.setCurrentIndex( + QStyleFactory.keys().index(self.style().objectName()) + ) + self.style_combo_box.currentIndexChanged.connect( + lambda: self.set_style(self.style_combo_box.currentData()) + ) self.control_layout.addWidget(self.style_combo_box) # -------- theme_combo_box --------------------------------------- @@ -155,7 +186,9 @@ class MainWindow(QMainWindow): self.theme_combo_box.addItem(theme, theme) self.theme_combo_box.setCurrentIndex(self.theme_combo_box.count() - 1) self.theme_combo_box.currentIndexChanged.connect( - lambda: self.visualisation_model.set_configuration(self.configurations[self.theme_combo_box.currentData()]) + lambda: self.visualisation_model.set_configuration( + self.configurations[self.theme_combo_box.currentData()] + ) ) self.control_layout.addWidget(self.theme_combo_box) @@ -217,7 +250,9 @@ class MainWindow(QMainWindow): self.load_button.clicked.connect(self.on_load) self.resource_dir_layout.addWidget(self.load_button) - def process_exception(self, e: Exception, heading: str = "", title: str | None = None): + def process_exception( + self, e: Exception, heading: str = "", title: str | None = None + ): if title is None: title = heading if isinstance(e, ValidationError): @@ -246,8 +281,12 @@ class MainWindow(QMainWindow): for theme in Theme: self.log_widget.appendPlainText(f"Loading {theme} ...") try: - config_path = Path( - self.resource_dir_line_widget.text()) / "roguelike" / theme / "recruitment.json" + config_path = ( + Path(self.resource_dir_line_widget.text()) + / "roguelike" + / theme + / "recruitment.json" + ) with open(config_path, encoding="utf-8") as fp: self.configurations[theme] = Configuration.json2config(fp.read()) except Exception as e: @@ -262,7 +301,9 @@ class MainWindow(QMainWindow): else: self.log_widget.insertPlainText("Succeeded!") else: - self.visualisation_model.set_configuration(self.configurations[self.theme_combo_box.currentData()]) + self.visualisation_model.set_configuration( + self.configurations[self.theme_combo_box.currentData()] + ) self.set_control_enabled(True) self.log_widget.appendPlainText(f"Done!") @@ -284,26 +325,43 @@ class MainWindow(QMainWindow): return selected_group_index = self.visualisation_model.get_selected_group_index() selected_oper_index = self.visualisation_model.get_selected_oper_index() - group_index_begin: int = selected_group_index if selected_group_index is not None else 0 - for group_index in range(group_index_begin, len(selected_configuration.priority)): + group_index_begin: int = ( + selected_group_index if selected_group_index is not None else 0 + ) + for group_index in range( + group_index_begin, len(selected_configuration.priority) + ): tmp_selected_group: Group = selected_configuration.priority[group_index] - oper_index_begin: int = selected_oper_index + 1 \ - if group_index == selected_group_index and selected_oper_index is not None \ + oper_index_begin: int = ( + selected_oper_index + 1 + if group_index == selected_group_index + and selected_oper_index is not None else 0 + ) for oper_index in range(oper_index_begin, len(tmp_selected_group.opers)): tmp_selected_oper = tmp_selected_group.opers[oper_index] if tmp_selected_oper.name == target_oper_name: - group_model_index = self.visualisation_model.group_list_model.index(group_index) + group_model_index = self.visualisation_model.group_list_model.index( + group_index + ) self.group_list_view.selectionModel().clearSelection() self.group_list_view.selectionModel().select( - group_model_index, self.group_list_view.selectionModel().Select) - self.group_list_view.scrollTo(group_model_index, self.group_list_view.PositionAtCenter) + group_model_index, self.group_list_view.selectionModel().Select + ) + self.group_list_view.scrollTo( + group_model_index, self.group_list_view.PositionAtCenter + ) - oper_model_index = self.visualisation_model.oper_list_model.index(oper_index) + oper_model_index = self.visualisation_model.oper_list_model.index( + oper_index + ) self.oper_list_view.selectionModel().clearSelection() self.oper_list_view.selectionModel().select( - oper_model_index, self.oper_list_view.selectionModel().Select) - self.oper_list_view.scrollTo(oper_model_index, self.oper_list_view.PositionAtCenter) + oper_model_index, self.oper_list_view.selectionModel().Select + ) + self.oper_list_view.scrollTo( + oper_model_index, self.oper_list_view.PositionAtCenter + ) break else: continue @@ -327,8 +385,12 @@ class MainWindow(QMainWindow): for theme in Theme: self.log_widget.appendPlainText(f"Saving {theme} ...") try: - config_path = Path( - self.resource_dir_line_widget.text()) / "roguelike" / theme / "recruitment.json" + config_path = ( + Path(self.resource_dir_line_widget.text()) + / "roguelike" + / theme + / "recruitment.json" + ) json_str = Configuration.config2json(self.configurations[theme]) with open(config_path, "w", encoding="utf-8") as fp: fp.write(json_str) diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/__init__.py index 0df9bf4bdc..a5f76221d9 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/__init__.py @@ -1,6 +1,3 @@ from .visualisation_model import VisualisationModel - -__all__ = [ - "VisualisationModel" -] +__all__ = ["VisualisationModel"] diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/group_list_model.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/group_list_model.py index ba9dfeb6b2..bd9e1307cc 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/group_list_model.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/group_list_model.py @@ -1,8 +1,7 @@ import pickle from typing import Callable -from PyQt5.QtCore import QAbstractListModel, QMimeData, QModelIndex, QVariant, Qt - +from PyQt5.QtCore import QAbstractListModel, QMimeData, QModelIndex, Qt, QVariant from roguelike.recruitment import Group from ..common import DocRole @@ -38,7 +37,12 @@ class GroupListModel(QAbstractListModel): def flags(self, index): default_flags = super().flags(index) if index.isValid(): - return default_flags | Qt.ItemIsEditable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled + return ( + default_flags + | Qt.ItemIsEditable + | Qt.ItemIsDragEnabled + | Qt.ItemIsDropEnabled + ) else: return default_flags | Qt.ItemIsDropEnabled @@ -80,7 +84,9 @@ class GroupListModel(QAbstractListModel): index = indexes[0] if index.isValid(): - mime_data.setData("application/x-custom-list-item", pickle.dumps(index.row())) + mime_data.setData( + "application/x-custom-list-item", pickle.dumps(index.row()) + ) return mime_data def dropMimeData(self, data, action, row, column, parent): diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_info_table_model.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_info_table_model.py index 0cfc76e602..c04a2af198 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_info_table_model.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_info_table_model.py @@ -1,5 +1,4 @@ -from PyQt5.QtCore import QAbstractTableModel, QModelIndex, QVariant, Qt - +from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt, QVariant from roguelike.recruitment import Oper from ..common import DescriptionRole, parse_field @@ -9,7 +8,7 @@ class OperInfoTableModel(QAbstractTableModel): def __init__(self, parent=None) -> None: super().__init__(parent) self._oper: Oper | None = None - self._field_list: list[str] = list(Oper.model_fields.keys())[: -2] + self._field_list: list[str] = list(Oper.model_fields.keys())[:-2] def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: if self._oper is None: diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_list_model.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_list_model.py index cb54fdbff1..552385d747 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_list_model.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_list_model.py @@ -1,8 +1,7 @@ import pickle from typing import Callable -from PyQt5.QtCore import QAbstractListModel, QMimeData, QModelIndex, QVariant, Qt - +from PyQt5.QtCore import QAbstractListModel, QMimeData, QModelIndex, Qt, QVariant from roguelike.recruitment import Oper from ..common import DocRole @@ -64,7 +63,9 @@ class OperListModel(QAbstractListModel): index = indexes[0] if index.isValid(): - mime_data.setData("application/x-custom-list-item", pickle.dumps(index.row())) + mime_data.setData( + "application/x-custom-list-item", pickle.dumps(index.row()) + ) return mime_data def dropMimeData(self, data, action, row, column, parent): diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_A_table_model.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_A_table_model.py index 7a9ac90ac8..001e513545 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_A_table_model.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_A_table_model.py @@ -1,7 +1,6 @@ import pickle -from PyQt5.QtCore import QAbstractTableModel, QMimeData, QModelIndex, QVariant, Qt - +from PyQt5.QtCore import QAbstractTableModel, QMimeData, QModelIndex, Qt, QVariant from roguelike.recruitment import RecruitPriorityOffset from ..common import parse_field @@ -56,7 +55,12 @@ class OperOffsetATableModel(QAbstractTableModel): def flags(self, index): default_flags = super().flags(index) if index.isValid(): - return default_flags | Qt.ItemIsEditable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled + return ( + default_flags + | Qt.ItemIsEditable + | Qt.ItemIsDragEnabled + | Qt.ItemIsDropEnabled + ) else: return default_flags | Qt.ItemIsDropEnabled @@ -83,7 +87,7 @@ class OperOffsetATableModel(QAbstractTableModel): return True return False -# ———————— drag & drop ——————————————————————————————————————————— + # ———————— drag & drop ——————————————————————————————————————————— def supportedDragActions(self): return Qt.MoveAction diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_B_table_model.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_B_table_model.py index 6c49ace269..656e9fa9d5 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_B_table_model.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/oper_offset_B_table_model.py @@ -1,7 +1,6 @@ import pickle -from PyQt5.QtCore import QAbstractTableModel, QMimeData, QModelIndex, QVariant, Qt - +from PyQt5.QtCore import QAbstractTableModel, QMimeData, QModelIndex, Qt, QVariant from roguelike.recruitment import CollectionPriorityOffset from ..common import parse_field @@ -49,7 +48,12 @@ class OperOffsetBTableModel(QAbstractTableModel): def flags(self, index): default_flags = super().flags(index) if index.isValid(): - return default_flags | Qt.ItemIsEditable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled + return ( + default_flags + | Qt.ItemIsEditable + | Qt.ItemIsDragEnabled + | Qt.ItemIsDropEnabled + ) else: return default_flags | Qt.ItemIsDropEnabled @@ -76,7 +80,7 @@ class OperOffsetBTableModel(QAbstractTableModel): return True return False -# ———————— drag & drop ——————————————————————————————————————————— + # ———————— drag & drop ——————————————————————————————————————————— def supportedDragActions(self): return Qt.MoveAction diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/visualisation_model.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/visualisation_model.py index 57c4b8bae9..66d277e962 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/visualisation_model.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/models/visualisation_model.py @@ -1,5 +1,4 @@ from PyQt5.QtCore import QItemSelection - from roguelike.recruitment import Configuration, Group, Oper from .group_list_model import GroupListModel @@ -16,13 +15,17 @@ class VisualisationModel: self.oper_info_model: OperInfoTableModel = OperInfoTableModel(parent) self.oper_offset_A_model: OperOffsetATableModel = OperOffsetATableModel(parent) self.oper_offset_B_model: OperOffsetBTableModel = OperOffsetBTableModel(parent) - self.group_list_model.extra_reset = lambda: (self.oper_list_model.set_oper_list(None), - self.oper_info_model.set_oper(None), - self.oper_offset_A_model.set_offset_list(None), - self.oper_offset_B_model.set_offset_list(None)) - self.oper_list_model.extra_reset = lambda: (self.oper_info_model.set_oper(None), - self.oper_offset_A_model.set_offset_list(None), - self.oper_offset_B_model.set_offset_list(None)) + self.group_list_model.extra_reset = lambda: ( + self.oper_list_model.set_oper_list(None), + self.oper_info_model.set_oper(None), + self.oper_offset_A_model.set_offset_list(None), + self.oper_offset_B_model.set_offset_list(None), + ) + self.oper_list_model.extra_reset = lambda: ( + self.oper_info_model.set_oper(None), + self.oper_offset_A_model.set_offset_list(None), + self.oper_offset_B_model.set_offset_list(None), + ) self._configuration: Configuration | None = None self._selected_group_index: int | None = None self._selected_oper_index: int | None = None @@ -31,7 +34,9 @@ class VisualisationModel: self._configuration = config self._selected_group_index = None self._selected_oper_index = None - self.group_list_model.set_group_list(self._configuration.priority if self._configuration is not None else None) + self.group_list_model.set_group_list( + self._configuration.priority if self._configuration is not None else None + ) def get_configuration(self) -> Configuration | None: return self._configuration @@ -42,7 +47,9 @@ class VisualisationModel: def get_selected_oper_index(self) -> int | None: return self._selected_oper_index - def on_group_selection(self, selected: QItemSelection, deselected: QItemSelection = None) -> None: + def on_group_selection( + self, selected: QItemSelection, deselected: QItemSelection = None + ) -> None: if not selected.indexes(): return self._selected_group_index = selected.indexes()[0].row() @@ -50,7 +57,9 @@ class VisualisationModel: selected_group: Group = self._configuration.priority[self._selected_group_index] self.oper_list_model.set_oper_list(selected_group.opers) - def on_oper_selection(self, selected: QItemSelection, deselected: QItemSelection = None) -> None: + def on_oper_selection( + self, selected: QItemSelection, deselected: QItemSelection = None + ) -> None: if not selected.indexes(): return self._selected_oper_index = selected.indexes()[0].row() @@ -58,4 +67,6 @@ class VisualisationModel: selected_oper: Oper = selected_group.opers[self._selected_oper_index] self.oper_info_model.set_oper(selected_oper) self.oper_offset_A_model.set_offset_list(selected_oper.recruit_priority_offsets) - self.oper_offset_B_model.set_offset_list(selected_oper.collection_priority_offsets) + self.oper_offset_B_model.set_offset_list( + selected_oper.collection_priority_offsets + ) diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/__init__.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/__init__.py index 0d9dbbd677..ffb3a37438 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/__init__.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/__init__.py @@ -5,12 +5,11 @@ from .oper_list_view import OperListView from .tab_bar import TabBar from .table_view import TableView - __all__ = [ "GroupListView", "OffsetATableView", "OffsetBTableView", "OperListView", "TabBar", - "TableView" + "TableView", ] diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/group_list_view.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/group_list_view.py index abc8352017..6a200351f2 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/group_list_view.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/group_list_view.py @@ -3,13 +3,12 @@ from typing import Optional from PyQt5.QtCore import Qt from PyQt5.QtGui import QCursor, QDrag, QKeyEvent from PyQt5.QtWidgets import QAction, QDialog, QListView, QMenu, QToolTip +from roguelike.recruitment import new_group from ..common import DocRole from ..delegates import EditableDelegate from ..dialogs import GroupEditDialog -from roguelike.recruitment import new_group - class GroupListView(QListView): def __init__(self, parent=None): @@ -53,19 +52,27 @@ class GroupListView(QListView): selected_group_index = selected_indices[0].row() insert_above_action = QAction("Insert Above", self) - insert_above_action.triggered.connect(lambda: self.create_group(selected_group_index)) + insert_above_action.triggered.connect( + lambda: self.create_group(selected_group_index) + ) context_menu.addAction(insert_above_action) insert_below_action = QAction("Insert Below", self) - insert_below_action.triggered.connect(lambda: self.create_group(selected_group_index + 1)) + insert_below_action.triggered.connect( + lambda: self.create_group(selected_group_index + 1) + ) context_menu.addAction(insert_below_action) update_action = QAction("Edit", self) - update_action.triggered.connect(lambda: self.update_group(selected_group_index)) + update_action.triggered.connect( + lambda: self.update_group(selected_group_index) + ) context_menu.addAction(update_action) delete_action = QAction("Delete", self) - delete_action.triggered.connect(lambda: self.delete_group(selected_group_index)) + delete_action.triggered.connect( + lambda: self.delete_group(selected_group_index) + ) context_menu.addAction(delete_action) else: insert_action = QAction("Insert", self) @@ -78,7 +85,9 @@ class GroupListView(QListView): group_list = self.model().get_group_list() group_list.insert(index, new_group()) self.model().set_group_list(group_list) - self.selectionModel().select(self.model().index(index), self.selectionModel().Select) + self.selectionModel().select( + self.model().index(index), self.selectionModel().Select + ) def update_group(self, index: int) -> None: group_list = self.model().get_group_list() @@ -104,4 +113,6 @@ class GroupListView(QListView): def dropEvent(self, event): super().dropEvent(event) self.selectionModel().clearSelection() - self.selectionModel().select(self.indexAt(event.pos()), self.selectionModel().Select) + self.selectionModel().select( + self.indexAt(event.pos()), self.selectionModel().Select + ) diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_A_table_view.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_A_table_view.py index 3ed3c4c6af..d320e60adf 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_A_table_view.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_A_table_view.py @@ -1,7 +1,6 @@ from PyQt5.QtCore import QItemSelection, QModelIndex, Qt from PyQt5.QtGui import QDrag from PyQt5.QtWidgets import QAction, QMenu - from roguelike.recruitment import new_recruit_priority_offset from .table_view import TableView @@ -34,15 +33,21 @@ class OffsetATableView(TableView): selected_group_index = selected_indices[0].row() insert_above_action = QAction("Insert Above", self) - insert_above_action.triggered.connect(lambda: self.create_offset(selected_group_index)) + insert_above_action.triggered.connect( + lambda: self.create_offset(selected_group_index) + ) context_menu.addAction(insert_above_action) insert_below_action = QAction("Insert Below", self) - insert_below_action.triggered.connect(lambda: self.create_offset(selected_group_index + 1)) + insert_below_action.triggered.connect( + lambda: self.create_offset(selected_group_index + 1) + ) context_menu.addAction(insert_below_action) delete_action = QAction("Delete", self) - delete_action.triggered.connect(lambda: self.delete_offset(selected_group_index)) + delete_action.triggered.connect( + lambda: self.delete_offset(selected_group_index) + ) context_menu.addAction(delete_action) else: insert_action = QAction("Insert", self) @@ -57,8 +62,12 @@ class OffsetATableView(TableView): self.model().set_offset_list(offset_list) new_selection_top_left: QModelIndex = self.model().index(index, 0) - new_selection_bottom_right: QModelIndex = self.model().index(index, self.model().columnCount() - 1) - new_selection: QItemSelection = QItemSelection(new_selection_top_left, new_selection_bottom_right) + new_selection_bottom_right: QModelIndex = self.model().index( + index, self.model().columnCount() - 1 + ) + new_selection: QItemSelection = QItemSelection( + new_selection_top_left, new_selection_bottom_right + ) self.selectionModel().select(new_selection, self.selectionModel().Select) def delete_offset(self, index: int) -> None: @@ -75,12 +84,21 @@ class OffsetATableView(TableView): drag.exec_(Qt.MoveAction) def dropEvent(self, event): - self.model().dropMimeData(event.mimeData(), event.proposedAction(), self.indexAt(event.pos()).row(), - self.indexAt(event.pos()).column(), QModelIndex()) + self.model().dropMimeData( + event.mimeData(), + event.proposedAction(), + self.indexAt(event.pos()).row(), + self.indexAt(event.pos()).column(), + QModelIndex(), + ) self.selectionModel().clearSelection() selected_row: int = self.indexAt(event.pos()).row() new_selection_top_left: QModelIndex = self.model().index(selected_row, 0) - new_selection_bottom_right: QModelIndex = self.model().index(selected_row, self.model().columnCount() - 1) - new_selection: QItemSelection = QItemSelection(new_selection_top_left, new_selection_bottom_right) + new_selection_bottom_right: QModelIndex = self.model().index( + selected_row, self.model().columnCount() - 1 + ) + new_selection: QItemSelection = QItemSelection( + new_selection_top_left, new_selection_bottom_right + ) self.selectionModel().select(new_selection, self.selectionModel().Select) diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_B_table_view.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_B_table_view.py index cf97e05c09..c1d15ea54c 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_B_table_view.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/offset_B_table_view.py @@ -1,7 +1,6 @@ from PyQt5.QtCore import QItemSelection, QModelIndex, Qt from PyQt5.QtGui import QDrag from PyQt5.QtWidgets import QAction, QMenu - from roguelike.recruitment import new_collection_priority_offset from .table_view import TableView @@ -34,15 +33,21 @@ class OffsetBTableView(TableView): selected_group_index = selected_indices[0].row() insert_above_action = QAction("Insert Above", self) - insert_above_action.triggered.connect(lambda: self.create_offset(selected_group_index)) + insert_above_action.triggered.connect( + lambda: self.create_offset(selected_group_index) + ) context_menu.addAction(insert_above_action) insert_below_action = QAction("Insert Below", self) - insert_below_action.triggered.connect(lambda: self.create_offset(selected_group_index + 1)) + insert_below_action.triggered.connect( + lambda: self.create_offset(selected_group_index + 1) + ) context_menu.addAction(insert_below_action) delete_action = QAction("Delete", self) - delete_action.triggered.connect(lambda: self.delete_offset(selected_group_index)) + delete_action.triggered.connect( + lambda: self.delete_offset(selected_group_index) + ) context_menu.addAction(delete_action) else: insert_action = QAction("Insert", self) @@ -55,7 +60,9 @@ class OffsetBTableView(TableView): oper_list = self.model().get_oper_list() oper_list.insert(index, new_collection_priority_offset()) self.model().set_oper_list(oper_list) - self.selectionModel().select(self.model().index(index), self.selectionModel().Select) + self.selectionModel().select( + self.model().index(index), self.selectionModel().Select + ) def delete_offset(self, index: int) -> None: offset_list = self.model().get_offset_list() @@ -71,12 +78,21 @@ class OffsetBTableView(TableView): drag.exec_(Qt.MoveAction) def dropEvent(self, event): - self.model().dropMimeData(event.mimeData(), event.proposedAction(), self.indexAt(event.pos()).row(), - self.indexAt(event.pos()).column(), QModelIndex()) + self.model().dropMimeData( + event.mimeData(), + event.proposedAction(), + self.indexAt(event.pos()).row(), + self.indexAt(event.pos()).column(), + QModelIndex(), + ) self.selectionModel().clearSelection() selected_row: int = self.indexAt(event.pos()).row() new_selection_top_left: QModelIndex = self.model().index(selected_row, 0) - new_selection_bottom_right: QModelIndex = self.model().index(selected_row, self.model().columnCount() - 1) - new_selection: QItemSelection = QItemSelection(new_selection_top_left, new_selection_bottom_right) + new_selection_bottom_right: QModelIndex = self.model().index( + selected_row, self.model().columnCount() - 1 + ) + new_selection: QItemSelection = QItemSelection( + new_selection_top_left, new_selection_bottom_right + ) self.selectionModel().select(new_selection, self.selectionModel().Select) diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/oper_list_view.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/oper_list_view.py index 77336bfeb0..26a2403b9a 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/oper_list_view.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/oper_list_view.py @@ -1,11 +1,9 @@ from typing import Optional +from pydantic import ValidationError from PyQt5.QtCore import Qt from PyQt5.QtGui import QCursor, QDrag, QKeyEvent from PyQt5.QtWidgets import QAction, QApplication, QListView, QMenu, QToolTip - -from pydantic import ValidationError - from roguelike.recruitment import Oper, new_oper from ..common import DocRole @@ -49,11 +47,15 @@ class OperListView(QListView): selected_oper_index = selected_indices[0].row() insert_above_action = QAction("Insert Above", self) - insert_above_action.triggered.connect(lambda: self.create_oper(selected_oper_index)) + insert_above_action.triggered.connect( + lambda: self.create_oper(selected_oper_index) + ) context_menu.addAction(insert_above_action) insert_below_action = QAction("Insert Below", self) - insert_below_action.triggered.connect(lambda: self.create_oper(selected_oper_index + 1)) + insert_below_action.triggered.connect( + lambda: self.create_oper(selected_oper_index + 1) + ) context_menu.addAction(insert_below_action) copy_action = QAction("Copy", self) @@ -62,15 +64,21 @@ class OperListView(QListView): if QApplication.clipboard().text(): paste_above_action = QAction("Paste Above", self) - paste_above_action.triggered.connect(lambda: self.paste_oper(selected_oper_index)) + paste_above_action.triggered.connect( + lambda: self.paste_oper(selected_oper_index) + ) context_menu.addAction(paste_above_action) paste_below_action = QAction("Paste Below", self) - paste_below_action.triggered.connect(lambda: self.paste_oper(selected_oper_index + 1)) + paste_below_action.triggered.connect( + lambda: self.paste_oper(selected_oper_index + 1) + ) context_menu.addAction(paste_below_action) delete_action = QAction("Delete", self) - delete_action.triggered.connect(lambda: self.delete_oper(selected_oper_index)) + delete_action.triggered.connect( + lambda: self.delete_oper(selected_oper_index) + ) context_menu.addAction(delete_action) else: insert_action = QAction("Insert", self) @@ -79,7 +87,9 @@ class OperListView(QListView): if QApplication.clipboard().text(): paste_action = QAction("Paste", self) - paste_action.triggered.connect(lambda: self.paste_oper(selected_oper_index)) + paste_action.triggered.connect( + lambda: self.paste_oper(selected_oper_index) + ) context_menu.addAction(paste_action) context_menu.exec_(self.viewport().mapToGlobal(pos)) @@ -88,10 +98,14 @@ class OperListView(QListView): oper_list = self.model().get_oper_list() oper_list.insert(index, new_oper()) self.model().set_oper_list(oper_list) - self.selectionModel().select(self.model().index(index), self.selectionModel().Select) + self.selectionModel().select( + self.model().index(index), self.selectionModel().Select + ) def copy_oper(self, index: int) -> None: - QApplication.clipboard().setText(Oper.oper2json(self.model().get_oper_list()[index])) + QApplication.clipboard().setText( + Oper.oper2json(self.model().get_oper_list()[index]) + ) def paste_oper(self, index: int) -> None: json_str = QApplication.clipboard().text() @@ -104,7 +118,9 @@ class OperListView(QListView): return oper_list.insert(index, pasted_oper) self.model().set_oper_list(oper_list) - self.selectionModel().select(self.model().index(index), self.selectionModel().Select) + self.selectionModel().select( + self.model().index(index), self.selectionModel().Select + ) def delete_oper(self, index: int) -> None: oper_list = self.model().get_oper_list() @@ -122,4 +138,6 @@ class OperListView(QListView): def dropEvent(self, event): super().dropEvent(event) self.selectionModel().clearSelection() - self.selectionModel().select(self.indexAt(event.pos()), self.selectionModel().Select) + self.selectionModel().select( + self.indexAt(event.pos()), self.selectionModel().Select + ) diff --git a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/table_view.py b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/table_view.py index c9f1c93f96..4b4e83f8e7 100644 --- a/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/table_view.py +++ b/tools/RoguelikeRecruitmentTool/roguelike_recruitment_tool/views/table_view.py @@ -26,9 +26,10 @@ class TableView(QTableView): if event.key() == Qt.Key_Q: index = self.indexAt(self.viewport().mapFromGlobal(QCursor.pos())) if index.isValid(): - content = (f"{self.model().data(index, Qt.DisplayRole).value()}" + - (f"\n{self.model().data(index, DescriptionRole).value()}" - if self.model().data(index, DescriptionRole).value() is not None - else "")) + content = f"{self.model().data(index, Qt.DisplayRole).value()}" + ( + f"\n{self.model().data(index, DescriptionRole).value()}" + if self.model().data(index, DescriptionRole).value() is not None + else "" + ) QToolTip.showText(QCursor.pos(), content) super().keyPressEvent(event) diff --git a/tools/TaskSorter/TaskSorter.py b/tools/TaskSorter/TaskSorter.py index daa01c8765..bf2cc9569b 100644 --- a/tools/TaskSorter/TaskSorter.py +++ b/tools/TaskSorter/TaskSorter.py @@ -1,10 +1,10 @@ - -import json -import re import argparse +import json import os +import re from pathlib import Path + def sort_tasks(res: dict[str, any]): classified_lists = { "UseSupportUnit...": [], @@ -20,7 +20,7 @@ def sort_tasks(res: dict[str, any]): "Reclamation@...": [], "Fire@Reclamation...": [], "Tales@RA...": [], - "...@Reclamation...": [] + "...@Reclamation...": [], } unclassified_list = [] @@ -39,7 +39,7 @@ def sort_tasks(res: dict[str, any]): (r"^Fire@Reclamation", classified_lists["Fire@Reclamation..."]), (r"^Tales@RA", classified_lists["Tales@RA..."]), (r"^(\w+)@Reclamation", classified_lists["...@Reclamation..."]), - (r"", unclassified_list) + (r"", unclassified_list), ] for k in res.keys(): @@ -50,9 +50,10 @@ def sort_tasks(res: dict[str, any]): return { k: res[k] - for k in unclassified_list + sum([ - sorted(target_list) - for target_list in classified_lists.values()], [])} + for k in unclassified_list + + sum([sorted(target_list) for target_list in classified_lists.values()], []) + } + def raise_on_duplicate_keys(pairs): """检查重复键,存在时抛出 ValueError""" @@ -63,12 +64,13 @@ def raise_on_duplicate_keys(pairs): seen[key] = value return seen + # 示例JSON数据(包含重复键) json_str = '{"name": "Alice", "age": 30, "name": "Bob"}' def main(cn_base_path, global_resources): - + cn_tasks = {} cn_order = {} # 使用 Path 处理路径,确保跨平台兼容 @@ -79,7 +81,9 @@ def main(cn_base_path, global_resources): continue file_path = Path(root) / file with open(file_path, "r", encoding="utf8") as f: - cn_tasks[file_path.relative_to(cn_base_path)] = json.load(f, object_pairs_hook=raise_on_duplicate_keys) + cn_tasks[file_path.relative_to(cn_base_path)] = json.load( + f, object_pairs_hook=raise_on_duplicate_keys + ) for task_path, task in cn_tasks.items(): cn_tasks[task_path] = sort_tasks(task) @@ -91,7 +95,9 @@ def main(cn_base_path, global_resources): continue for task in tasks: if task in tasks1: - raise ValueError(f"Duplicate task found: {task_path} and {task_path1} have the same task '{task}'") + raise ValueError( + f"Duplicate task found: {task_path} and {task_path1} have the same task '{task}'" + ) for task_path, task in cn_tasks.items(): cn_tasks[task_path] = sort_tasks(task) @@ -99,7 +105,11 @@ def main(cn_base_path, global_resources): with open(cn_base_path / task_path, "w", encoding="utf8", newline="\n") as f: json.dump(task, f, ensure_ascii=False, indent=4) - print("CN:", str(sum(len(tasks) for tasks in cn_order.values())).rjust(4, " "), "tasks") + print( + "CN:", + str(sum(len(tasks) for tasks in cn_order.values())).rjust(4, " "), + "tasks", + ) for server, path in global_resources.items(): overseas_path = Path(path) @@ -120,10 +130,19 @@ def main(cn_base_path, global_resources): tasks = { k: { x: tasks[k][x] - for x in sorted(tasks[k].keys(), - key=lambda x: list(base_tasks[k].keys()).index(x) if k in base_tasks and x in base_tasks[k] else -1) + for x in sorted( + tasks[k].keys(), + key=lambda x: ( + list(base_tasks[k].keys()).index(x) + if k in base_tasks and x in base_tasks[k] + else -1 + ), + ) } - for k in sorted(tasks.keys(), key=lambda k: base_order.index(k) if k in base_order else -1) + for k in sorted( + tasks.keys(), + key=lambda k: base_order.index(k) if k in base_order else -1, + ) } with open(file_path, "w", encoding="utf8", newline="\n") as f: @@ -131,10 +150,15 @@ def main(cn_base_path, global_resources): count += len(tasks) print(server + ":", str(count).rjust(4, " "), "tasks") -if __name__ == '__main__': + +if __name__ == "__main__": parser = argparse.ArgumentParser(description="Sort tasks in JSON files.") parser.add_argument("--cn", type=str, help="Path to the CN tasks JSON file.") - parser.add_argument("--overseas", type=str, help="Comma-separated paths to the global tasks JSON files in the format 'EN:path,JP:path,KR:path,TW:path'.") + parser.add_argument( + "--overseas", + type=str, + help="Comma-separated paths to the global tasks JSON files in the format 'EN:path,JP:path,KR:path,TW:path'.", + ) args = parser.parse_args() resource_dir = Path(__file__).parents[2] / "resource" @@ -144,11 +168,14 @@ if __name__ == '__main__': "EN": resource_dir / "global/YoStarEN/resource/tasks", "JP": resource_dir / "global/YoStarJP/resource/tasks", "KR": resource_dir / "global/YoStarKR/resource/tasks", - "TW": resource_dir / "global/txwy/resource/tasks" + "TW": resource_dir / "global/txwy/resource/tasks", } global_resources = default_global_resources if args.overseas: - global_resources = {k: Path(v) for k, v in (item.split(':') for item in args.overseas.split(','))} + global_resources = { + k: Path(v) + for k, v in (item.split(":") for item in args.overseas.split(",")) + } main(cn_task_path, global_resources) diff --git a/tools/maadeps-download.py b/tools/maadeps-download.py index f2bd4128a6..2230771281 100644 --- a/tools/maadeps-download.py +++ b/tools/maadeps-download.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3 import argparse -import os -import sys -import urllib.request -import urllib.error -import json -import time -import platform -from pathlib import Path -import shutil import http.client +import json +import os +import platform +import shutil +import sys +import time +import urllib.error +import urllib.request +from pathlib import Path TARGET_TAG = "v2.10.0-maa.1" basedir = Path(__file__).parent.parent @@ -30,7 +30,7 @@ def detect_host_triplet(): raise Exception("unsupported architecture: " + machine) if system in {"windows", "linux"}: pass - elif 'mingw' in system or 'cygwin' in system: + elif "mingw" in system or "cygwin" in system: system = "windows" elif system == "darwin": system = "osx" @@ -62,7 +62,7 @@ class ProgressHook: f"\r [{self.downloaded / total * 100.0:3.1f}%] ", f"{format_size(self.downloaded)} / {format_size(total)}", " \r", - end='' + end="", ) if self.downloaded == total: print("") @@ -71,9 +71,9 @@ class ProgressHook: def sanitize_filename(filename: str): system = platform.system() if system == "Windows": - filename = filename.translate( - str.maketrans("/\\:\"?*|\0", "________") - ).rstrip('.') + filename = filename.translate(str.maketrans('/\\:"?*|\0', "________")).rstrip( + "." + ) elif system == "Darwin": filename = filename.translate(str.maketrans("/:\0", "___")) else: @@ -84,12 +84,10 @@ def sanitize_filename(filename: str): def retry_urlopen(*args, **kwargs): for _ in range(5): try: - resp: http.client.HTTPResponse = urllib.request.urlopen(*args, - **kwargs) + resp: http.client.HTTPResponse = urllib.request.urlopen(*args, **kwargs) return resp except urllib.error.HTTPError as e: - if (e.status == 403 and - e.headers.get("x-ratelimit-remaining") == "0"): + if e.status == 403 and e.headers.get("x-ratelimit-remaining") == "0": # rate limit t0 = time.time() reset_time = t0 + 10 @@ -100,7 +98,7 @@ def retry_urlopen(*args, **kwargs): reset_time = max(reset_time, t0 + 10) print( "rate limit exceeded, retrying after ", - f"{reset_time - t0:.1f} seconds" + f"{reset_time - t0:.1f} seconds", ) time.sleep(reset_time - t0) continue @@ -111,8 +109,12 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument("target_triplet", nargs="?", default=None) parser.add_argument("tag", nargs="?", default=None) - parser.add_argument("-f", "--force", action="store_true", - help="force download even if already exists") + parser.add_argument( + "-f", + "--force", + action="store_true", + help="force download even if already exists", + ) args = parser.parse_args() if args.target_triplet is not None: @@ -126,16 +128,16 @@ def main(): target_tag = TARGET_TAG print( "About to download prebuilt dependency libraries for", - f"{target_triplet} of {target_tag}" + f"{target_triplet} of {target_tag}", ) if args.target_triplet is None: print( "to specify another triplet [and tag], ", - f"run `{sys.argv[0]} [tag]`" + f"run `{sys.argv[0]} [tag]`", ) print( f"e.g. `{sys.argv[0]} arm64-windows` ", - f"or `{sys.argv[0]} arm64-windows 2023-04-24-3`" + f"or `{sys.argv[0]} arm64-windows 2023-04-24-3`", ) maadeps_dir = Path(basedir, "MaaDeps") @@ -148,7 +150,7 @@ def main(): if not args.force and versions.get(target_triplet) == target_tag: print( f"prebuilt dependencies for {target_triplet} of {target_tag} ", - "already exist, skipping download" + "already exist, skipping download", ) print(f"to force download, run `{sys.argv[0]} -f`") return @@ -163,13 +165,14 @@ def main(): releases = json.loads(resp) def split_asset_name(name: str): - *remainder, component_suffix = name.rsplit('-', 1) + *remainder, component_suffix = name.rsplit("-", 1) component = component_suffix.split(".", 1)[0] if remainder: _, *target = remainder[0].split("-", 1) if target: return target[0], component return None, None + devel_asset = None runtime_asset = None for release in releases: @@ -178,9 +181,9 @@ def main(): for asset in release["assets"]: target, component = split_asset_name(asset["name"]) if target == target_triplet: - if component == 'devel': + if component == "devel": devel_asset = asset - elif component == 'runtime': + elif component == "runtime": runtime_asset = asset if devel_asset and runtime_asset: break @@ -191,16 +194,18 @@ def main(): download_dir = Path(maadeps_dir, "tarball") download_dir.mkdir(parents=True, exist_ok=True) try: - shutil.rmtree(maadeps_dir / "runtime" / f"maa-{target_triplet}", - ignore_errors=True) - shutil.rmtree(maadeps_dir / "vcpkg" / "installed" / - f"maa-{target_triplet}", ignore_errors=True) + shutil.rmtree( + maadeps_dir / "runtime" / f"maa-{target_triplet}", ignore_errors=True + ) + shutil.rmtree( + maadeps_dir / "vcpkg" / "installed" / f"maa-{target_triplet}", + ignore_errors=True, + ) for asset in [devel_asset, runtime_asset]: - url = asset['browser_download_url'] + url = asset["browser_download_url"] print("downloading from", url) local_file = download_dir / sanitize_filename(asset["name"]) - urllib.request.urlretrieve(url, local_file, - reporthook=ProgressHook()) + urllib.request.urlretrieve(url, local_file, reporthook=ProgressHook()) print("extracting", asset["name"]) shutil.unpack_archive(local_file, maadeps_dir) versions[target_triplet] = target_tag