mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-10 06:50:33 +08:00
Compare commits
3 Commits
v6.3.2
...
docs/task-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78c1ff3a5c | ||
|
|
53052833f4 | ||
|
|
cd17cced22 |
@@ -1,26 +0,0 @@
|
||||
FROM mcr.microsoft.com/devcontainers/base:ubuntu
|
||||
|
||||
USER vscode
|
||||
|
||||
ENV PATH="/home/vscode/.local/bin:${PATH}"
|
||||
|
||||
ARG PYTHON_VERSION=3.12.11
|
||||
ARG NODEJS_VERSION=24
|
||||
|
||||
# Install and setup mise and uv
|
||||
RUN curl https://mise.run | sh
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Activate mise
|
||||
RUN echo 'eval "$(mise activate bash)"' >> ~/.bashrc
|
||||
|
||||
# Setup Python and Node.js
|
||||
RUN mise use -g node@$NODEJS_VERSION
|
||||
RUN uv python install $PYTHON_VERSION
|
||||
|
||||
# Create and activate venv
|
||||
RUN uv venv --clear ~/.venv/maa
|
||||
RUN echo "source ~/.venv/maa/bin/activate" >> ~/.bashrc
|
||||
|
||||
# Install tools
|
||||
RUN uv tool install prek
|
||||
@@ -1,48 +0,0 @@
|
||||
// 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",
|
||||
"esbenp.prettier-vscode",
|
||||
"DavidAnson.vscode-markdownlint",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"vue.volar",
|
||||
"mkxml.vscode-filesize"
|
||||
],
|
||||
"settings": {
|
||||
// Color theme
|
||||
"workbench.colorTheme": "Default Dark Modern",
|
||||
|
||||
// Editor formatting
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
|
||||
// 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"
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
WORKSPACE=$(pwd)
|
||||
|
||||
echo "===================="
|
||||
cd "$WORKSPACE"
|
||||
echo "Setting up git safe.directory..."
|
||||
git config --global --add safe.directory "$WORKSPACE"
|
||||
git submodule foreach --recursive 'git config --global --add safe.directory "$toplevel/$path"'
|
||||
|
||||
echo "===================="
|
||||
cd "$WORKSPACE"
|
||||
echo "Updating submodules..."
|
||||
git submodule update --init --recursive
|
||||
|
||||
echo "===================="
|
||||
cd "$WORKSPACE"/docs
|
||||
echo "Installing node modules..."
|
||||
npm install -g pnpm
|
||||
pnpm install --frozen-lockfile
|
||||
@@ -1,52 +0,0 @@
|
||||
FROM mcr.microsoft.com/devcontainers/base:ubuntu
|
||||
|
||||
USER vscode
|
||||
|
||||
ENV PATH="/home/vscode/.local/bin:${PATH}"
|
||||
|
||||
ARG CLANGD_VERSION=20
|
||||
ARG PYTHON_VERSION=3.12.11
|
||||
ARG NODEJS_VERSION=24
|
||||
|
||||
# Add kitware's apt repository (for cmake)
|
||||
RUN curl -fsSL https://apt.kitware.com/keys/kitware-archive-latest.asc | sudo gpg --dearmor -o /usr/share/keyrings/kitware-archive-keyring.gpg
|
||||
RUN cat <<EOF | sudo tee /etc/apt/sources.list.d/kitware.sources
|
||||
Types: deb
|
||||
URIs: https://apt.kitware.com/ubuntu
|
||||
Suites: $(lsb_release -cs)
|
||||
Components: main
|
||||
Architectures: $(dpkg --print-architecture)
|
||||
Signed-By: /usr/share/keyrings/kitware-archive-keyring.gpg
|
||||
EOF
|
||||
|
||||
# Install system dependencies
|
||||
RUN sudo apt update \
|
||||
&& sudo apt upgrade -y \
|
||||
&& sudo apt install -y \
|
||||
cmake \
|
||||
fish \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Initialize fish
|
||||
RUN fish -c exit
|
||||
|
||||
# Install and setup mise and uv
|
||||
RUN curl https://mise.run | sh
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Activate mise
|
||||
RUN echo 'eval "$(mise activate bash)"' >> ~/.bashrc
|
||||
RUN echo 'mise activate fish | source' >> ~/.config/fish/config.fish
|
||||
|
||||
# Setup Python and Node.js
|
||||
RUN mise use -g node@$NODEJS_VERSION
|
||||
RUN uv python install $PYTHON_VERSION
|
||||
|
||||
# Create and activate venv
|
||||
RUN uv venv --clear ~/.venv/maa
|
||||
RUN echo "source ~/.venv/maa/bin/activate" >> ~/.bashrc
|
||||
RUN echo "source ~/.venv/maa/bin/activate.fish" >> ~/.config/fish/config.fish
|
||||
|
||||
# Install tools
|
||||
RUN uv tool install prek
|
||||
RUN uv tool install ruff
|
||||
@@ -1,78 +0,0 @@
|
||||
// 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",
|
||||
"charliermarsh.ruff",
|
||||
"esbenp.prettier-vscode",
|
||||
"DavidAnson.vscode-markdownlint",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"vue.volar",
|
||||
"mkxml.vscode-filesize"
|
||||
],
|
||||
"settings": {
|
||||
// Color theme
|
||||
"workbench.colorTheme": "Default Dark Modern",
|
||||
|
||||
// Editor formatting
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
|
||||
// Language-specific formatting
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "charliermarsh.ruff",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit"
|
||||
}
|
||||
},
|
||||
"[cpp]": {
|
||||
"editor.defaultFormatter": "xaver.clang-format"
|
||||
},
|
||||
"[c]": {
|
||||
"editor.defaultFormatter": "xaver.clang-format"
|
||||
},
|
||||
|
||||
// Python runtime
|
||||
"python.terminal.launchArgs": ["-u"],
|
||||
"python.defaultInterpreterPath": "/home/vscode/.venv/maa/bin/python",
|
||||
"python.terminal.activateEnvironment": false,
|
||||
|
||||
// CMake settings
|
||||
"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"
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
WORKSPACE=$(pwd)
|
||||
|
||||
echo "===================="
|
||||
cd "$WORKSPACE"
|
||||
echo "Setting up git safe.directory..."
|
||||
git config --global --add safe.directory "$WORKSPACE"
|
||||
git submodule foreach --recursive 'git config --global --add safe.directory "$toplevel/$path"'
|
||||
|
||||
echo "===================="
|
||||
cd "$WORKSPACE"
|
||||
echo "Updating submodules..."
|
||||
git submodule update --init --recursive
|
||||
|
||||
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"
|
||||
uv 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"
|
||||
uv 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/src/MaaUtils/MaaDeps/x-tools/llvm/bin/clang-format /usr/local/bin/clang-format
|
||||
sudo ln -s $WORKSPACE/src/MaaUtils/MaaDeps/x-tools/llvm/bin/clangd /usr/local/bin/clangd
|
||||
29
.devcontainer/Dockerfile
Normal file
29
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
FROM mcr.microsoft.com/devcontainers/base:ubuntu
|
||||
|
||||
USER vscode
|
||||
|
||||
ENV CONDA_DIR=/home/vscode/miniconda
|
||||
ENV PATH="$CONDA_DIR/bin:$PATH"
|
||||
|
||||
ARG PYTHON_VERSION=3.12
|
||||
ARG NODEJS_VERSION=24
|
||||
|
||||
# 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 python=$PYTHON_VERSION -y \
|
||||
&& conda activate maa \
|
||||
&& conda install -y conda-forge::nodejs=$NODEJS_VERSION \
|
||||
&& pip install pre-commit black \
|
||||
&& npm install -g pnpm
|
||||
|
||||
# Finalize conda setup
|
||||
RUN conda init \
|
||||
&& conda config --set auto_activate false \
|
||||
&& echo "conda activate maa" >> ~/.bashrc
|
||||
@@ -1,13 +1,50 @@
|
||||
// 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": "Plain Env (Nothing Installed)",
|
||||
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
|
||||
"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": {
|
||||
// Color theme
|
||||
"workbench.colorTheme": "Default Dark Modern"
|
||||
// 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"
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
#!/bin/bash
|
||||
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..."
|
||||
git config --global --add safe.directory "$WORKSPACE"
|
||||
git submodule foreach --recursive 'git config --global --add safe.directory "$toplevel/$path"'
|
||||
|
||||
echo "===================="
|
||||
cd "$WORKSPACE"
|
||||
echo "Updating submodules..."
|
||||
git submodule update --init --recursive
|
||||
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
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
@@ -46,13 +46,9 @@ e3d63894b28b2ef5e2405e144a32a6981de5e1b2
|
||||
# refactor: divide tasks.json into multiple jsons
|
||||
dce6e317c8e56836662b64ac4b3d1a69b4ff4dd8
|
||||
|
||||
# c# 统一使用文件范围限定的 namespace
|
||||
76252d42e3febae1aef396e8ee5482fa46d565c6
|
||||
|
||||
# usage: add "[blame ignore]" to the commit message
|
||||
# This file is managed by an automated workflow
|
||||
# Do not add, remove or modify lines below this comment
|
||||
# as they are automatically appended
|
||||
# --------------------------------------------------- #
|
||||
f7772bc814c52f9a5e65af02404cf54b70fe0a32
|
||||
ca9807ce099e5cae133293df8dfcd2b56b0e06bd
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -10,5 +10,3 @@
|
||||
*.md text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.yaml text eol=lf
|
||||
|
||||
*.sh text eol=lf
|
||||
|
||||
2
.github/.last-blame-ignore-commit
vendored
2
.github/.last-blame-ignore-commit
vendored
@@ -1 +1 @@
|
||||
1944164d9c47549d71c3b25987e9299404cc16f3
|
||||
272d71fa2938f945832f86232532b86a9e5406b8
|
||||
|
||||
20
.github/ISSUE_TEMPLATE/cn-bug-report.yaml
vendored
20
.github/ISSUE_TEMPLATE/cn-bug-report.yaml
vendored
@@ -41,9 +41,11 @@ body:
|
||||
attributes:
|
||||
label: 日志和配置文件
|
||||
description: |
|
||||
**请在 MAA -> 设置 -> 问题反馈中找到生成日志压缩包按钮,点击并上传压缩包**
|
||||
**若待上传压缩包大于 25MB,请转而上传该压缩包同日期文件夹中的若干小压缩包**
|
||||
若正在使用 macOS,请点击屏幕左上角的“文件”,点击“打开日志文件夹”
|
||||
**请在 MAA -> 设置 -> 问题反馈中找到生成日志压缩包按钮,点击并上传压缩包**
|
||||
|
||||
**请直接将完整的文件拖拽进来,而非自己裁切或复制的片段;若文件体积过大可压缩后再上传**
|
||||
|
||||
如果你在使用 MacBook,请点击屏幕左上角的“文件”,点击“打开日志文件夹”
|
||||
placeholder: |
|
||||
请确认上传文件前已关闭 MAA
|
||||
validations:
|
||||
@@ -53,8 +55,8 @@ body:
|
||||
attributes:
|
||||
label: 配置信息
|
||||
description: |
|
||||
请说明操作系统及版本、模拟器品牌、模拟器分辨率、DPI、帧率
|
||||
若正在使用 MuMu 或雷电 9,请说明截图增强是否开启
|
||||
请说明操作系统及版本、模拟器品牌、模拟器分辨率、DPI、帧率;
|
||||
若正在使用 MuMu 或雷电 9,请说明截图增强是否开启;
|
||||
最后请说明 GPU 加速推理是否开启,若开启请提供 GPU 型号。
|
||||
validations:
|
||||
required: true
|
||||
@@ -63,9 +65,11 @@ body:
|
||||
attributes:
|
||||
label: 截图或录屏
|
||||
description: |
|
||||
可上传屏幕截图或录制以帮助解释你的问题,包括但不限于 MAA 软件截图、游戏画面截图
|
||||
若是**识别相关问题**,请尽可能提供模拟器自带的截图工具截取的无遮挡的**原图**(或通过 adb 截取原图)
|
||||
用其他的工具(如QQ/微信)截取的图片包含窗口边框且长宽比、分辨率不固定,不利于我们排除bug
|
||||
`debug` 目录下按功能分类的文件夹内,有一些自动截图的错误图片,若有相关的,请一并打包上传
|
||||
|
||||
可上传屏幕截图或录制以帮助解释你的问题,包括但不限于 MAA 软件截图、游戏画面截图
|
||||
若是**识别相关问题**,请尽可能提供模拟器自带的截图工具截取的无遮挡的**原图**(或通过 adb 截取原图)
|
||||
用其他的工具(如QQ/微信)截取的图片包含窗口边框且长宽比、分辨率不固定,不利于我们排除bug
|
||||
若文件体积过大可压缩后再上传
|
||||
validations:
|
||||
required: false
|
||||
|
||||
25
.github/ISSUE_TEMPLATE/en-bug-report.yaml
vendored
25
.github/ISSUE_TEMPLATE/en-bug-report.yaml
vendored
@@ -43,9 +43,11 @@ body:
|
||||
attributes:
|
||||
label: Log and config files
|
||||
description: |
|
||||
**Please locate the Generate Support Payload button under MAA Settings -> Issue Report, click the button, and upload the generated zip file**
|
||||
**If the archive to upload is larger than 25MB, please upload smaller archives from the same date folder instead.**
|
||||
If you are using macOS, please click the "File" option in the top-left corner of the screen, then click "Open Log Folder".
|
||||
**Please locate the Generate Support Payload button under MAA Settings -> Issue Report, click the button, and upload the generated zip file**
|
||||
|
||||
**Please drag and drop the full file in, not your own cuttings or copies; compress it before uploading if too large.**
|
||||
|
||||
If you are using MacBook, please click the "File" option in the top-left corner of the screen, then click "Open Log Folder".
|
||||
placeholder: |
|
||||
Please confirm that MAA is not running before uploading files.
|
||||
validations:
|
||||
@@ -55,8 +57,8 @@ body:
|
||||
attributes:
|
||||
label: Configuration information
|
||||
description: |
|
||||
Please specify the operating system and version, emulator brand, emulator resolution, DPI, and frame rate.
|
||||
If you are using MuMu or LDPlayer 9, please specify whether Screenshot Enhancement is enabled.
|
||||
Please specify the operating system and version, emulator brand, emulator resolution, DPI, and frame rate;
|
||||
If you are using MuMu or LDPlayer 9, please specify whether Screenshot Enhancement is enabled;
|
||||
Finally, please specify whether GPU accelerated inference is enabled, and if so, provide the GPU model.
|
||||
validations:
|
||||
required: true
|
||||
@@ -65,15 +67,22 @@ body:
|
||||
attributes:
|
||||
label: Screenshots or recordings
|
||||
description: |
|
||||
In the `debug` directory, within the functionally categorized folders,
|
||||
there are some error images captured automatically.
|
||||
If related to this issue, please upload them together.
|
||||
|
||||
If available, upload screenshots and recordings to help explain your problem,
|
||||
including but not limited to screenshots of MAA software,
|
||||
screenshots of game screens.
|
||||
screenshots of game screens.
|
||||
|
||||
If the problem is **recognition related**, please help by providing
|
||||
the **original image** taken by the emulator's own screenshot tool
|
||||
(or via adb).
|
||||
(or via adb).
|
||||
|
||||
Screenshots taken with other tools may contain the frames of the window/emulator
|
||||
and their aspect ratio and resolution are inconsistent,
|
||||
which makes it harder for us to debug.
|
||||
which makes it harder for us to debug.
|
||||
|
||||
If the file size is too large, you may compress it before uploading.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
1
.github/dependabot.yaml
vendored
1
.github/dependabot.yaml
vendored
@@ -9,7 +9,6 @@ updates:
|
||||
assignees:
|
||||
- AnnAngela
|
||||
- Constrat
|
||||
- lucienshawls
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
|
||||
4
.github/issue-checker.yml
vendored
4
.github/issue-checker.yml
vendored
@@ -252,7 +252,7 @@ labels:
|
||||
# `module: fight`
|
||||
- name: fight
|
||||
content: "module: fight"
|
||||
regexes: "刷图|理智|剿灭|刷.{0,6}材料|关卡选择|战斗|作战|[戰戦][鬥闘]|[Ff]ight|[Bb]attle|[Aa]nihilation"
|
||||
regexes: "刷图|刷理智|剿灭|刷.{0,6}材料|关卡选择|战斗|作战|[戰戦][鬥闘]|[Ff]ight|[Bb]attle|[Aa]nihilation"
|
||||
skip-if:
|
||||
- skip all
|
||||
- skip module
|
||||
@@ -335,7 +335,7 @@ labels:
|
||||
# `MacGui`
|
||||
- name: MacGui
|
||||
content: "client: MacGui"
|
||||
regexes: '(?:[Mm][Aa][Cc](?:[Bb][Oo][Oo][Kk]|[Oo][Ss]|\s*(?:操作系统|系统|电脑|版|[Gg][Uu][Ii]))|[Pp][Ll][Aa][Yy][Cc][Oo][Vv][Ee][Rr]|[Mm][Aa][Cc]\s+[Gg][Uu][Ii])'
|
||||
regexes: '/mac(?:book|os|\s*(?:操作系统|系统|电脑|版))|playcover/i'
|
||||
skip-if:
|
||||
- skip all
|
||||
- skip client
|
||||
|
||||
62
.github/pr_cache_remover.ps1
vendored
62
.github/pr_cache_remover.ps1
vendored
@@ -1,46 +1,38 @@
|
||||
$totalClearedSize = 0
|
||||
$cacheList = gh cache list --json id,ref,sizeInBytes | ConvertFrom-Json
|
||||
$branchSet = @{}
|
||||
git ls-remote --heads origin | ForEach-Object {
|
||||
if ($_ -match 'refs/heads/(.+)$') { $branchSet[$matches[1]] = $true }
|
||||
$prCaches = $cacheList | Where-Object { $_.ref -like "*merge*" }
|
||||
|
||||
if (-not $prCaches) {
|
||||
Write-Output "No PR caches found."
|
||||
exit
|
||||
}
|
||||
|
||||
foreach ($cache in $cacheList) {
|
||||
$shouldDelete = $false
|
||||
foreach ($cache in $prCaches) {
|
||||
$cacheId = $cache.id
|
||||
$cacheRef = $cache.ref
|
||||
$cacheSizeInBytes = $cache.sizeInBytes
|
||||
|
||||
if ($cache.ref -match "refs/pull/(\d+)/merge") {
|
||||
if ($cacheRef -match "refs/pull/(\d+)/merge") {
|
||||
$prNumber = $matches[1]
|
||||
|
||||
Write-Host "PR #${prNumber}: " -NoNewline
|
||||
|
||||
try {
|
||||
$prStatus = (gh pr view $prNumber --json state | ConvertFrom-Json).state
|
||||
Write-Host "$prStatus" -NoNewline
|
||||
$shouldDelete = $prStatus -in @("MERGED", "CLOSED")
|
||||
}
|
||||
catch {
|
||||
Write-Host "NOT FOUND" -NoNewline
|
||||
$shouldDelete = $true
|
||||
}
|
||||
}
|
||||
elseif ($cache.ref -match "refs/heads/(.+)" -and $matches[1] -ne "dev") {
|
||||
$branchName = $matches[1]
|
||||
$exists = $branchSet.ContainsKey($branchName)
|
||||
|
||||
Write-Host "Branch '$branchName': $(if ($exists) { 'EXISTS' } else { 'DELETED' })" -NoNewline
|
||||
$shouldDelete = -not $exists
|
||||
}
|
||||
else {
|
||||
continue
|
||||
}
|
||||
|
||||
$prStatus = gh pr view $prNumber --json state | ConvertFrom-Json
|
||||
|
||||
Write-Host $prStatus.state -NoNewline
|
||||
|
||||
if ($prStatus.state -eq "MERGED" -or $prStatus.state -eq "CLOSED") {
|
||||
Write-Host " -> DELETING"
|
||||
|
||||
gh cache delete $cacheId
|
||||
|
||||
if ($shouldDelete) {
|
||||
Write-Host " -> DELETING"
|
||||
gh cache delete $cache.id
|
||||
$totalClearedSize += $cache.sizeInBytes
|
||||
}
|
||||
else {
|
||||
Write-Host ""
|
||||
$totalClearedSize += $cacheSizeInBytes
|
||||
}
|
||||
else {
|
||||
Write-Host ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Cleared size: $("{0:N2}" -f ($totalClearedSize / 1MB)) MB"
|
||||
$formattedSize = "{0:N2}" -f ($totalClearedSize / 1MB)
|
||||
Write-Output "Cleared size: $formattedSize MB"
|
||||
|
||||
3
.github/stale_cache_cleanup.ps1
vendored
3
.github/stale_cache_cleanup.ps1
vendored
@@ -11,8 +11,7 @@ $keyPatterns = @(
|
||||
"macOS-arm64-maadeps",
|
||||
"Linux-x64-maadeps",
|
||||
"Linux-arm64-maadeps",
|
||||
"Smoke-testing",
|
||||
"prek-v1|Linux|X64"
|
||||
"Smoke-testing"
|
||||
)
|
||||
|
||||
# Filter caches matching any of our key patterns
|
||||
|
||||
3
.github/stale_cache_dev.ps1
vendored
3
.github/stale_cache_dev.ps1
vendored
@@ -19,8 +19,7 @@ $keyPatterns = @(
|
||||
"macOS-arm64-maadeps",
|
||||
"Linux-x64-maadeps",
|
||||
"Linux-arm64-maadeps",
|
||||
"Smoke-testing",
|
||||
"prek-v1|Linux|X64"
|
||||
"Smoke-testing"
|
||||
)
|
||||
|
||||
foreach ($pattern in $keyPatterns) {
|
||||
|
||||
8
.github/workflows/blame-ignore.yml
vendored
8
.github/workflows/blame-ignore.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Blame Ignore Update
|
||||
name: Git Blame Ignore
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -7,20 +7,18 @@ on:
|
||||
|
||||
jobs:
|
||||
blame-ignore:
|
||||
name: Update Git Blame Ignore Revs
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false # Needed to bypass protection rules in Push changes
|
||||
|
||||
- name: Check blame
|
||||
id: check_changes
|
||||
continue-on-error: true
|
||||
run: |
|
||||
LAST_CHECKED_COMMIT=$(cat .github/.last-blame-ignore-commit 2>/dev/null || git rev-list --max-parents=0 HEAD)
|
||||
|
||||
@@ -28,7 +26,7 @@ jobs:
|
||||
|
||||
git diff --quiet .git-blame-ignore-revs
|
||||
|
||||
- name: Commit changes
|
||||
- name: Commit and Push changes
|
||||
if: ${{ steps.check_changes.outcome == 'failure' }}
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
|
||||
5
.github/workflows/cache-delete.yml
vendored
5
.github/workflows/cache-delete.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Cache Cleanup
|
||||
name: Delete Cache
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -11,14 +11,13 @@ on:
|
||||
|
||||
jobs:
|
||||
cache-delete:
|
||||
name: Delete PR Cache
|
||||
# Run only on organization branches with PRs
|
||||
if: github.event_name == 'workflow_dispatch' ||
|
||||
github.event.pull_request.head.repo.full_name ==
|
||||
github.event.pull_request.base.repo.full_name
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Delete PR cache
|
||||
- name: Delete cache on PR merged
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||||
PR_NUMBER=${{ github.event.inputs.pr_number }}
|
||||
|
||||
347
.github/workflows/ci.yml
vendored
347
.github/workflows/ci.yml
vendored
@@ -1,80 +1,85 @@
|
||||
name: Release Pipeline
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
branches-ignore:
|
||||
- "master"
|
||||
paths:
|
||||
- "3rdparty/include/**"
|
||||
- "include/**"
|
||||
- "src/**"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- ".github/workflows/ci.yml"
|
||||
- "!**/*.md"
|
||||
- "tools/maadeps-download.py"
|
||||
pull_request:
|
||||
branches:
|
||||
- "dev"
|
||||
paths:
|
||||
- ".github/workflows/ci.yml"
|
||||
- "3rdparty/include/**"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- "CMakePresets.json"
|
||||
- "include/**"
|
||||
- "src/**"
|
||||
- "tools/maadeps-download.py"
|
||||
- "!**/*.md"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/ci.yml"
|
||||
- "3rdparty/include/**"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- "CMakePresets.json"
|
||||
- "include/**"
|
||||
- "src/**"
|
||||
- "tools/maadeps-download.py"
|
||||
- "!**/*.md"
|
||||
- "tools/maadeps-download.py"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.head_ref || github.ref_name }}${{ github.ref == 'refs/heads/dev' && format('-{0}', github.sha) || '' }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
name: Gather Meta Information
|
||||
# Prevent duplicate runs on organization branches with PRs
|
||||
if: github.event_name != 'pull_request' ||
|
||||
github.event.pull_request.head.repo.full_name !=
|
||||
github.event.pull_request.base.repo.full_name
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
tag: ${{ steps.set_tag.outputs.tag }}
|
||||
prerelease: ${{ steps.set_pre.outputs.prerelease }}
|
||||
steps:
|
||||
- name: Show concurrency group
|
||||
run: |
|
||||
echo "Concurrency Group: ${{ github.workflow }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.head_ref || github.ref_name }}${{ github.ref == 'refs/heads/dev' && format('-{0}', github.sha) || '' }}"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
path: temp
|
||||
show-progress: false
|
||||
|
||||
- name: Fetch history
|
||||
if: ${{ !startsWith(github.ref, 'refs/pull/') }}
|
||||
run: |
|
||||
git init
|
||||
cp $GITHUB_WORKSPACE/temp/.git/config ./.git
|
||||
rm -rf $GITHUB_WORKSPACE/temp
|
||||
# git config remote.origin.fetch '+refs/*:refs/*'
|
||||
git fetch --filter=tree:0 # --update-head-ok
|
||||
git reset --hard origin/$(git branch --show-current) || true
|
||||
git checkout ${{ github.ref_name }}
|
||||
|
||||
- name: Set tag
|
||||
id: set_tag
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
# For tag pushes, use the tag name
|
||||
tag="${{ github.ref_name }}"
|
||||
else
|
||||
# For PRs and branch pushes, use git describe or fallback
|
||||
tag=$(git describe --tags --match "v*" HEAD 2>/dev/null || echo "v0.0.1-$(git rev-parse --short HEAD)")
|
||||
fi
|
||||
echo "tag=${tag}" | tee -a $GITHUB_OUTPUT
|
||||
${{ startsWith(github.ref, 'refs/pull/') && 'cd temp' || '' }}
|
||||
echo tag=$(git describe --tags --match "v*" ${{ github.ref }} || git rev-parse --short HEAD) | tee -a $GITHUB_OUTPUT
|
||||
exit ${PIPESTATUS[0]}
|
||||
|
||||
- name: Check if it is a pre-release
|
||||
- name: Judge pre-release
|
||||
id: set_pre
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
run: |
|
||||
if [[ '${{ steps.set_tag.outputs.tag }}' =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "prerelease=false" | tee -a $GITHUB_OUTPUT
|
||||
echo prerelease=false | tee -a $GITHUB_OUTPUT
|
||||
else
|
||||
echo "prerelease=true" | tee -a $GITHUB_OUTPUT
|
||||
echo prerelease=true | tee -a $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Finalize changelog
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
- name: Generate changelog
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
run: |
|
||||
this_tag=${{ steps.set_tag.outputs.tag }}
|
||||
if [[ '${{ steps.set_pre.outputs.prerelease }}' != 'false' ]]; then
|
||||
@@ -87,15 +92,19 @@ jobs:
|
||||
echo >> CHANGELOG.md
|
||||
echo "[已有 Mirror酱 CDK?前往 Mirror酱 高速下载](https://mirrorchyan.com/zh/projects?rid=MAA&source=maagh-release)" >> CHANGELOG.md
|
||||
|
||||
- name: Upload changelog to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
- name: Upload changelog to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
with:
|
||||
name: changelog
|
||||
path: CHANGELOG.md
|
||||
|
||||
windows:
|
||||
name: Build for Windows
|
||||
# Prevent duplicate runs on organization branches with PRs
|
||||
if: github.event_name != 'pull_request' ||
|
||||
github.event.pull_request.head.repo.full_name !=
|
||||
github.event.pull_request.base.repo.full_name
|
||||
|
||||
needs: meta
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -104,23 +113,21 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Fetch submodules
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaUtils
|
||||
git submodule update --init --depth 1 3rdparty/EmulatorExtras
|
||||
|
||||
- name: Cache MaaDeps
|
||||
id: cache-maadeps
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
./src/MaaUtils/MaaDeps
|
||||
./MaaDeps
|
||||
key: ${{ runner.os }}-${{ matrix.arch }}-maadeps-${{ hashFiles('tools/maadeps-download.py') }}
|
||||
|
||||
- name: Bootstrap MaaDeps
|
||||
@@ -130,31 +137,23 @@ jobs:
|
||||
run: |
|
||||
python3 tools/maadeps-download.py ${{ matrix.arch }}-windows
|
||||
|
||||
- name: Configure, build and install
|
||||
- name: Config cmake
|
||||
run: |
|
||||
cmake -B build --preset ${{ matrix.arch == 'arm64' && 'windows-publish-arm64' || 'windows-publish-x64' }} -DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}'
|
||||
cmake --build --preset ${{ matrix.arch == 'arm64' && 'windows-publish-arm64' || 'windows-publish-x64' }} --parallel $env:NUMBER_OF_PROCESSORS
|
||||
cmake --install build --config RelWithDebInfo
|
||||
mkdir -p build
|
||||
cmake -B build ${{ matrix.arch == 'arm64' && '-A ARM64' }} -DCMAKE_BUILD_TYPE=Release -DMAADEPS_TRIPLET='maa-${{ matrix.arch }}-windows' -DINSTALL_RESOURCE=ON -DINSTALL_PYTHON=ON -DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}' -DBUILD_WPF_GUI=OFF
|
||||
|
||||
- name: Download MaaFramework
|
||||
if: matrix.arch == 'x64'
|
||||
uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
repository: MaaXYZ/MaaFramework
|
||||
latest: true
|
||||
fileName: '*win-x86_64*.zip'
|
||||
extract: true
|
||||
out-file-path: MaaFramework-temp
|
||||
|
||||
- name: Copy MaaWin32ControlUnit
|
||||
if: matrix.arch == 'x64'
|
||||
- name: Build
|
||||
run: |
|
||||
cp MaaFramework-temp/bin/*Win32ControlUnit* install/
|
||||
cmake --build build --config Release --parallel $env:NUMBER_OF_PROCESSORS
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
mkdir -p install
|
||||
cmake --install build --prefix install --config Release
|
||||
|
||||
- name: Cache .nuke/temp, ~/.nuget/packages
|
||||
id: cache-nuget
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.nuke/temp
|
||||
@@ -165,7 +164,7 @@ jobs:
|
||||
if: steps.cache-nuget.outputs.cache-hit != 'true'
|
||||
run: dotnet restore src/MaaWpfGui/MaaWpfGui.csproj
|
||||
|
||||
- name: Taggify version for csproj
|
||||
- name: Taggify Version for csproj
|
||||
run: |
|
||||
$csprojPath = "src/MaaWpfGui/MaaWpfGui.csproj"
|
||||
$csprojPath = Resolve-Path -Path $csprojPath
|
||||
@@ -186,24 +185,11 @@ jobs:
|
||||
- name: Publish WPF GUI
|
||||
continue-on-error: true
|
||||
run: |
|
||||
dotnet publish src/MaaWpfGui/MaaWpfGui.csproj -c Release -p:Platform=${{ matrix.arch == 'arm64' && 'ARM64' || 'x64' }} -o install
|
||||
dotnet publish src/MaaWpfGui/MaaWpfGui.csproj -c Release -o install
|
||||
|
||||
- name: Collect PDB files
|
||||
run: |
|
||||
cp build/bin/RelWithDebInfo/*.pdb install/
|
||||
Compress-Archive -Path install/*.pdb -DestinationPath install/MAAComponent-DebugSymbol-${{ needs.meta.outputs.tag }}-win-${{ matrix.arch }}.zip
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload PDB files
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: MAAComponent-DebugSymbol-win-${{ matrix.arch }}
|
||||
path: install/MAAComponent-DebugSymbol-${{ needs.meta.outputs.tag }}-win-${{ matrix.arch }}.zip
|
||||
|
||||
- name: Organize install files
|
||||
- name: Organize Install Files
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf install/MAAComponent-DebugSymbol-*.zip
|
||||
rm -rf install/*.pdb
|
||||
rm -rf install/msvc-debug
|
||||
rm -rf install/*.h
|
||||
@@ -215,14 +201,18 @@ jobs:
|
||||
cd install
|
||||
Compress-Archive -Destination MAA-${{ needs.meta.outputs.tag }}-win-${{ matrix.arch }}.zip -Path ./*
|
||||
|
||||
- name: Upload MAA to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload MAA to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MAA-win-${{ matrix.arch }}
|
||||
path: install/MAA-*.zip
|
||||
path: install/*.zip
|
||||
|
||||
ubuntu:
|
||||
name: Build for Ubuntu
|
||||
# Prevent duplicate runs on organization branches with PRs
|
||||
if: github.event_name != 'pull_request' ||
|
||||
github.event.pull_request.head.repo.full_name !=
|
||||
github.event.pull_request.base.repo.full_name
|
||||
|
||||
needs: meta
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -230,23 +220,21 @@ jobs:
|
||||
arch: [aarch64, x86_64]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Fetch submodules
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaUtils
|
||||
git submodule update --init --depth 1 3rdparty/EmulatorExtras
|
||||
git submodule update --init --depth 1 src/maa-cli
|
||||
|
||||
- name: Cache MaaDeps
|
||||
id: cache-maadeps
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./src/MaaUtils/MaaDeps
|
||||
path: ./MaaDeps
|
||||
key: ${{ runner.os }}-${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-maadeps-${{ hashFiles('tools/maadeps-download.py') }}
|
||||
|
||||
- name: Bootstrap MaaDeps
|
||||
@@ -256,25 +244,40 @@ jobs:
|
||||
run: |
|
||||
python3 tools/maadeps-download.py ${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-linux
|
||||
|
||||
- name: Configure, build and install
|
||||
- name: Config cmake
|
||||
run: |
|
||||
cmake --preset ${{ matrix.arch == 'x86_64' && 'linux-publish-x64' || 'linux-publish-arm64' }} -DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}'
|
||||
cmake --build --preset ${{ matrix.arch == 'x86_64' && 'linux-publish-x64' || 'linux-publish-arm64' }} --parallel $(nproc)
|
||||
cmake --install build --config RelWithDebInfo
|
||||
mkdir -p build
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DMAADEPS_TRIPLET='maa-${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-linux' \
|
||||
-DINSTALL_RESOURCE=ON \
|
||||
-DINSTALL_PYTHON=ON \
|
||||
-DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}' \
|
||||
-DCMAKE_TOOLCHAIN_FILE=MaaDeps/cmake/maa-${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-linux-toolchain.cmake
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake --build build --config Release --parallel $(nproc)
|
||||
env:
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
- name: Setup cross compile toolchains for CLI
|
||||
- name: Install
|
||||
run: |
|
||||
mkdir -p install
|
||||
cmake --install build --prefix install --config Release
|
||||
|
||||
- name: Setup Cross Compile Toolchains for CLI
|
||||
uses: ./src/maa-cli/.github/actions/setup
|
||||
with:
|
||||
os: ubuntu-latest
|
||||
target_arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Build CLI
|
||||
run: |
|
||||
cargo build --release --locked --package maa-cli --features git2/vendored-openssl
|
||||
cargo build --release --locked --package maa-cli --features vendored-openssl
|
||||
cp -v target/$CARGO_BUILD_TARGET/release/maa $GITHUB_WORKSPACE/install/maa
|
||||
cargo build --release --locked --package maa-cli --no-default-features \
|
||||
--features git2,git2/vendored-openssl
|
||||
--features git2,vendored-openssl
|
||||
cp -v target/$CARGO_BUILD_TARGET/release/maa $GITHUB_WORKSPACE/appimage-maa
|
||||
working-directory: src/maa-cli
|
||||
|
||||
@@ -320,8 +323,8 @@ jobs:
|
||||
cd install
|
||||
tar czvf $GITHUB_WORKSPACE/release/MAA-${{ needs.meta.outputs.tag }}-linux-${{ matrix.arch }}.tar.gz .
|
||||
|
||||
- name: Upload MAA to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload MAA to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MAA-linux-${{ matrix.arch }}
|
||||
path: |
|
||||
@@ -329,65 +332,78 @@ jobs:
|
||||
release/*.tar.gz
|
||||
|
||||
macOS-Core:
|
||||
name: Build Core for macOS
|
||||
# Prevent duplicate runs on organization branches with PRs
|
||||
if: github.event_name != 'pull_request' ||
|
||||
github.event.pull_request.head.repo.full_name !=
|
||||
github.event.pull_request.base.repo.full_name
|
||||
|
||||
needs: meta
|
||||
runs-on: macos-26
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [arm64, x86_64]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Fetch submodules
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaUtils
|
||||
|
||||
# ninja 1.13.1 is already installed and up-to-date.
|
||||
# - name: Install dependencies
|
||||
# - name: Install Dependencies
|
||||
# run: |
|
||||
# brew install ninja
|
||||
|
||||
- name: Cache MaaDeps
|
||||
id: cache-maadeps
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./src/MaaUtils/MaaDeps
|
||||
path: ./MaaDeps
|
||||
key: ${{ runner.os }}-${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-maadeps-${{ hashFiles('tools/maadeps-download.py') }}
|
||||
|
||||
- name: Bootstrap MaaDeps
|
||||
run: |
|
||||
python3 tools/maadeps-download.py ${{ matrix.arch == 'x86_64' && 'x64' || 'arm64' }}-osx
|
||||
[[ ${{ matrix.arch }} = "arm64" ]] && triplet="arm64-osx" || triplet="x64-osx"
|
||||
python3 tools/maadeps-download.py ${triplet}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Configure, build and install
|
||||
- name: Config cmake
|
||||
run: |
|
||||
cmake -B build --preset ${{ matrix.arch == 'x86_64' && 'macos-publish-x64' || 'macos-publish-arm64' }} -DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}'
|
||||
cmake --build --preset ${{ matrix.arch == 'x86_64' && 'macos-publish-x64' || 'macos-publish-arm64' }} --parallel $(sysctl -n hw.logicalcpu)
|
||||
cmake --install build --config RelWithDebInfo
|
||||
cmake -B build -GNinja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_OSX_ARCHITECTURES='${{ matrix.arch }}' \
|
||||
-DMAA_HASH_VERSION='${{ needs.meta.outputs.tag }}'
|
||||
|
||||
- name: Upload MAA to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Build
|
||||
run: |
|
||||
cmake --build build --config Release --parallel $(sysctl -n hw.logicalcpu)
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --prefix install --config Release
|
||||
|
||||
- name: Upload MAA to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MAACore-macos-${{ matrix.arch }}
|
||||
path: "install/*.dylib"
|
||||
|
||||
macOS-GUI:
|
||||
name: Build GUI for macOS
|
||||
# Prevent duplicate runs on organization branches with PRs
|
||||
if: github.event_name != 'pull_request' ||
|
||||
github.event.pull_request.head.repo.full_name !=
|
||||
github.event.pull_request.base.repo.full_name
|
||||
|
||||
needs: [meta, macOS-Core]
|
||||
runs-on: macos-26
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Install dependencies
|
||||
- name: Install Dependencies
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: |
|
||||
brew install graphicsmagick imagemagick
|
||||
@@ -397,47 +413,47 @@ jobs:
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaMacGui
|
||||
|
||||
- name: Download MAA (arm64) from GitHub
|
||||
uses: actions/download-artifact@v7
|
||||
- name: Download Arm64 MAA from Github
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: MAACore-macos-arm64
|
||||
path: install-arm64
|
||||
|
||||
- name: Download MAA (x64) from GitHub
|
||||
uses: actions/download-artifact@v7
|
||||
- name: Download x64 MAA from Github
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: MAACore-macos-x86_64
|
||||
path: install-x86_64
|
||||
|
||||
- name: Install Developer ID certificate
|
||||
- name: Install Developer ID Certificate
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: apple-actions/import-codesign-certs@v6
|
||||
uses: apple-actions/import-codesign-certs@v5
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.HGUANDL_SIGN_CERT_P12 }}
|
||||
p12-password: ${{ secrets.HGUANDL_SIGN_CERT_PASSWD }}
|
||||
|
||||
- name: Download provisioning profiles
|
||||
- name: Download Provisioning Profiles
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: apple-actions/download-provisioning-profiles@v5
|
||||
uses: apple-actions/download-provisioning-profiles@v4
|
||||
with:
|
||||
bundle-id: "com.hguandl.MeoAsstMac"
|
||||
issuer-id: ${{ secrets.HGUANDL_APPSTORE_ISSUER }}
|
||||
api-key-id: ${{ secrets.HGUANDL_APPSTORE_KEYID }}
|
||||
api-private-key: ${{ secrets.HGUANDL_APPSTORE_KEY }}
|
||||
|
||||
- name: Setup Xcode toolchain
|
||||
if: false
|
||||
- name: Setup Xcode Toolchain
|
||||
if: true
|
||||
run: |
|
||||
sudo xcode-select -s /Applications/Xcode_16.1.app/Contents/Developer
|
||||
|
||||
- name: Build universal binaries
|
||||
- name: Build Universal Binaries
|
||||
run: |
|
||||
mkdir build
|
||||
for LIB_NAME in $(ls install-arm64); do
|
||||
lipo -create install-arm64/$LIB_NAME install-x86_64/$LIB_NAME -output build/$LIB_NAME
|
||||
done
|
||||
|
||||
- name: Archive runtime files
|
||||
- name: Archive Runtime Files
|
||||
run: |
|
||||
mkdir runtime && cd runtime
|
||||
name='MAA-${{ needs.meta.outputs.tag }}-macos-runtime-universal'
|
||||
@@ -449,8 +465,8 @@ jobs:
|
||||
cd .. || exit 1
|
||||
zip -yrX9 "$name.zip" "$name"
|
||||
|
||||
- name: Upload MAA runtime to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload MAA runtime to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MAA-macos-runtime-universal
|
||||
path: runtime/MAA-${{ needs.meta.outputs.tag }}-macos-runtime-universal.zip
|
||||
@@ -458,13 +474,12 @@ jobs:
|
||||
- name: Build XCFramework
|
||||
run: |
|
||||
xcodebuild -create-xcframework -library libMaaCore.dylib -headers ../include -output MaaCore.xcframework
|
||||
xcodebuild -create-xcframework -library libMaaUtils.dylib -output MaaUtils.xcframework
|
||||
xcodebuild -create-xcframework -library libfastdeploy_ppocr.dylib -output fastdeploy_ppocr.xcframework
|
||||
xcodebuild -create-xcframework -library libonnxruntime.*.dylib -output ONNXRuntime.xcframework
|
||||
xcodebuild -create-xcframework -library libopencv*.dylib -output OpenCV.xcframework
|
||||
working-directory: build
|
||||
|
||||
- name: Setup GUI version
|
||||
- name: Setup GUI Version
|
||||
run: |
|
||||
RELEASE_COUNT=$(git ls-remote --tags origin | grep refs/tags/v | awk 'END{print NR}')
|
||||
echo 'MARKETING_VERSION = ${{ needs.meta.outputs.tag }}' | tee src/MaaMacGui/Version.xcconfig
|
||||
@@ -485,20 +500,20 @@ jobs:
|
||||
xcodebuild -exportArchive -archivePath MAA.xcarchive -exportOptionsPlist ExportOptions.plist -exportPath Export
|
||||
working-directory: src/MaaMacGui
|
||||
|
||||
- name: Create disk image
|
||||
- name: Create Disk Image
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: |
|
||||
create-dmg Export/MAA.app
|
||||
mv MAA*.dmg MAA.dmg
|
||||
working-directory: src/MaaMacGui
|
||||
|
||||
- name: Archive debug symbols
|
||||
- name: Archive Debug Symbols
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: |
|
||||
ditto -c -k --keepParent MAA.app.dSYM MAA.app.dSYM.zip
|
||||
working-directory: src/MaaMacGui/MAA.xcarchive/dSYMs
|
||||
|
||||
- name: Place packages
|
||||
- name: Place Packages
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: |
|
||||
GIT_TAG=${{ needs.meta.outputs.tag }}
|
||||
@@ -508,7 +523,7 @@ jobs:
|
||||
mv src/MaaMacGui/MAA.dmg release/${APP_DMG}
|
||||
mv src/MaaMacGui/MAA.xcarchive/dSYMs/MAA.app.dSYM.zip release/${APP_SYM}
|
||||
|
||||
- name: Notarize image
|
||||
- name: Notarize Image
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
@@ -524,31 +539,34 @@ jobs:
|
||||
APPSTORE_KEY: ${{ secrets.HGUANDL_APPSTORE_KEY }}
|
||||
ISSUER_ID: ${{ secrets.HGUANDL_APPSTORE_ISSUER }}
|
||||
|
||||
- name: Attach notarization tickets
|
||||
- name: Attach Notarization Tickets
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
run: |
|
||||
dmg="MAA-${{ needs.meta.outputs.tag }}-macos-universal.dmg"
|
||||
xcrun stapler staple ${dmg}
|
||||
working-directory: release
|
||||
|
||||
- name: Upload MAA to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload MAA to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MAA-macos-universal
|
||||
path: ${{ startsWith(github.ref, 'refs/tags/v') && 'release/MAA*' || 'src/MaaMacGui/MAA.xcarchive/**' }}
|
||||
|
||||
release:
|
||||
name: Publish Release
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
# Prevent duplicate runs on organization branches with PRs
|
||||
if: (github.event_name != 'pull_request' ||
|
||||
github.event.pull_request.head.repo.full_name !=
|
||||
github.event.pull_request.base.repo.full_name) && startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
needs: [meta, windows, ubuntu, macOS-Core, macOS-GUI]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download MAA from GitHub
|
||||
uses: actions/download-artifact@v7
|
||||
- name: Download MAA from Github
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: assets
|
||||
|
||||
- name: Clean up files
|
||||
- name: Cleanup files
|
||||
run: |
|
||||
mv -vf assets/changelog/* .
|
||||
rm -rf assets/MAACore-macos-*
|
||||
@@ -556,35 +574,32 @@ jobs:
|
||||
# find . -type f | xargs mv -fvt .
|
||||
find . -type f | while read f; do mv -fvt . $f; done
|
||||
|
||||
- name: Publish release to GitHub
|
||||
uses: softprops/action-gh-release@v2.5.0
|
||||
- name: Release to Github
|
||||
uses: softprops/action-gh-release@v2.3.3
|
||||
with:
|
||||
body_path: CHANGELOG.md
|
||||
files: |
|
||||
assets/*
|
||||
prerelease: ${{ needs.meta.outputs.prerelease != 'false' }}
|
||||
|
||||
- name: Trigger release distribution workflows
|
||||
- name: Trigger MirrorChyan
|
||||
run: |
|
||||
gh workflow run --repo $GITHUB_REPOSITORY release-package-distribution.yml \
|
||||
-f release_tag="${{ needs.meta.outputs.tag }}" \
|
||||
-f mirrorchyan=true \
|
||||
-f winget=${{ needs.meta.outputs.prerelease == 'false' }}
|
||||
gh workflow run --repo $GITHUB_REPOSITORY mirrorchyan_release_note.yml
|
||||
gh workflow run --repo $GITHUB_REPOSITORY mirrorchyan
|
||||
gh workflow run --repo $GITHUB_REPOSITORY mirrorchyan_release_note
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Trigger OTA release workflow # ref: https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow
|
||||
- name: Trigger secondary workflows # ref: https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow
|
||||
run: |
|
||||
gh workflow run --repo $GITHUB_REPOSITORY release-ota.yml
|
||||
gh workflow run --repo $GITHUB_REPOSITORY release-ota
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.MISTEOWORKFLOW }}
|
||||
|
||||
- name: Create issue on failure
|
||||
- name: Create issue if failed
|
||||
if: failure()
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: "create-issue"
|
||||
title: "Errors occured during release ${{ needs.meta.outputs.tag }}"
|
||||
title: "Failed Release"
|
||||
body: |
|
||||
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
|
||||
57
.github/workflows/codeql-core.yml
vendored
Normal file
57
.github/workflows/codeql-core.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: "CodeQL MaaCore and MaaWpfGui Analysis"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: ["dev"]
|
||||
paths:
|
||||
- "3rdparty/include/**"
|
||||
- "include/**"
|
||||
- "src/**"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- ".github/workflows/codeql-core.yml"
|
||||
- "!**/*.md"
|
||||
- "!**/*.xaml"
|
||||
schedule:
|
||||
- cron: "45 11 * * *" # Runs daily at 11:45 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
contents: read
|
||||
packages: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
analyze-manual:
|
||||
name: Analyze MaaCore and MaaWpfGui
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Setup CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: c-cpp,csharp
|
||||
build-mode: manual
|
||||
|
||||
- name: Run CodeQL
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:multi-manual"
|
||||
|
||||
- name: Delete old caches
|
||||
shell: pwsh
|
||||
run: |
|
||||
$oldCaches = gh cache list --key codeql --order asc --json key | ConvertFrom-Json | Select-Object -SkipLast 1
|
||||
foreach ($cache in $oldCaches) {
|
||||
if ($cache.key) {
|
||||
Write-Host "Deleting cache: $($cache.key)"
|
||||
gh cache delete $cache.key
|
||||
}
|
||||
}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
36
.github/workflows/codeql-wf.yml
vendored
Normal file
36
.github/workflows/codeql-wf.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: "CodeQL Workflows Analysis"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: ["dev"]
|
||||
paths:
|
||||
- ".github/**/*.yml"
|
||||
schedule:
|
||||
- cron: "00 12 * * *" # Runs daily at 12:00 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
analyze-workflows:
|
||||
name: Analyze GitHub Workflows
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Setup CodeQL for GitHub Actions
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: actions
|
||||
build-mode: none
|
||||
|
||||
- name: Run CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:multi-none"
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Release Preparation
|
||||
name: gen-changelog
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -9,19 +9,18 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
generate-changelog:
|
||||
name: Generate Changelog
|
||||
gen:
|
||||
# startsWith 表达式不区分大小写
|
||||
if: github.event.pull_request.draft == false && startsWith(github.event.pull_request.title, 'Release v')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
show-progress: false
|
||||
|
||||
- name: Extract release information
|
||||
- name: Extract tag name
|
||||
id: extract_tag
|
||||
env:
|
||||
PR_BODY: ${{ format('{0}/{1}', runner.temp, 'output' ) }}
|
||||
@@ -51,7 +50,7 @@ jobs:
|
||||
|
||||
echo 'Target PR: ${{ github.event.pull_request.html_url }}' >> $PR_BODY
|
||||
echo '' >> $PR_BODY
|
||||
echo '<details><summary>Debug information</summary>' >> $PR_BODY
|
||||
echo '<details><summary>Debug info</summary>' >> $PR_BODY
|
||||
echo '' >> $PR_BODY
|
||||
echo '```' >> $PR_BODY
|
||||
sed 's/=/: /1' $GITHUB_OUTPUT >> $PR_BODY
|
||||
@@ -61,14 +60,14 @@ jobs:
|
||||
|
||||
cat $PR_BODY
|
||||
|
||||
- name: Generate changelog
|
||||
- name: Generate Changelog
|
||||
run: |
|
||||
git switch dev
|
||||
python3 tools/ChangelogGenerator/changelog_generator.py --tag "${{ steps.extract_tag.outputs.tag_name }}" --latest "${{ steps.extract_tag.outputs.latest }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Commit changes
|
||||
- name: Add files to git
|
||||
run: |
|
||||
git status
|
||||
|
||||
@@ -79,8 +78,8 @@ jobs:
|
||||
commit_msg="docs: Auto Generate Changelog of Release ""${{ steps.extract_tag.outputs.tag_name }}"
|
||||
git commit -m "$commit_msg"
|
||||
|
||||
- name: Create changelog PR
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
- name: Create PR
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
sign-commits: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -94,18 +93,7 @@ jobs:
|
||||
assignees: |
|
||||
AnnAngela
|
||||
|
||||
- name: Assign reviewers to release PR
|
||||
uses: kentaro-m/auto-assign-action@v2.0.1
|
||||
- name: Add reviewers to release PR
|
||||
uses: kentaro-m/auto-assign-action@v2.0.0
|
||||
with:
|
||||
configuration-path: ".github/release_reviewers.yaml"
|
||||
|
||||
update-submodules:
|
||||
name: Update Submodules
|
||||
if: github.event.pull_request.draft == false && startsWith(github.event.pull_request.title, 'Release v')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Trigger submodule update workflow
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh workflow run --repo $GITHUB_REPOSITORY update-submodules.yml
|
||||
7
.github/workflows/issue-checkbox-checker.yml
vendored
7
.github/workflows/issue-checkbox-checker.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Issue Review
|
||||
name: Auto Close not reading issues or Fold checkboxes
|
||||
|
||||
on:
|
||||
issues:
|
||||
@@ -6,7 +6,6 @@ on:
|
||||
|
||||
jobs:
|
||||
check-then-close-or-fold:
|
||||
name: Review and Modify Issues
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
@@ -64,7 +63,7 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
- name: Check for issue checkboxes
|
||||
- name: Check checkbox status
|
||||
id: unread-checkbox-check
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
@@ -87,7 +86,7 @@ jobs:
|
||||
'I have checked all the options without carefully reading the content and believe this will not affect issue resolution.'];
|
||||
return texts.some(text => new RegExp(`- \\[x\\]\\s*${text}`).test(context.payload.issue.body));
|
||||
|
||||
- name: Close low-quality issue
|
||||
- name: Close and lock issue
|
||||
if: steps.unread-checkbox-check.outputs.result == 'true'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
|
||||
6
.github/workflows/issue-checker.yml
vendored
6
.github/workflows/issue-checker.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Issue Triage
|
||||
name: "Issue Checker"
|
||||
|
||||
on:
|
||||
issues:
|
||||
@@ -15,11 +15,9 @@ permissions:
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
name: Triage Issues and PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Label issues and PRs Automatically
|
||||
uses: MaaAssistantArknights/issue-checker@v1.14
|
||||
- uses: MaaAssistantArknights/issue-checker@v1.14
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
configuration-path: .github/issue-checker.yml
|
||||
|
||||
24
.github/workflows/markdown-checker.yml
vendored
24
.github/workflows/markdown-checker.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Markdown Link Check
|
||||
name: Check Dead Links
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -7,22 +7,22 @@ on:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- ".github/workflows/markdown-checker.yml"
|
||||
- "docs/**"
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
- ".github/workflows/markdown-checker.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- ".github/workflows/markdown-checker.yml"
|
||||
- "docs/**"
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
- ".github/workflows/markdown-checker.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check-links:
|
||||
name: Check Dead Links
|
||||
if: github.repository_owner == 'MaaAssistantArknights' && github.event.head_commit.author.email != '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
name: Check Dead Links
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
@@ -30,19 +30,19 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Cache lychee responses
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
- name: Cache Primes
|
||||
id: cache-primes
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .lycheecache
|
||||
key: lychee-cache
|
||||
|
||||
- name: Check dead internal links
|
||||
- name: Check dead links
|
||||
uses: lycheeverse/lychee-action@v2
|
||||
with:
|
||||
# 仅检查内部链接,排除所有外部链接
|
||||
|
||||
71
.github/workflows/mirrorchyan.yml
vendored
Normal file
71
.github/workflows/mirrorchyan.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: mirrorchyan
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
mirrorchyan:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- name: Upload MAA win x64
|
||||
uses: MirrorChyan/uploading-action@v1
|
||||
if: always()
|
||||
with:
|
||||
filetype: latest-release
|
||||
filename: "*MAA-*-win-x64.zip"
|
||||
mirrorchyan_rid: MAA
|
||||
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
upload_token: ${{ secrets.MirrorChyanUploadToken }}
|
||||
os: win
|
||||
arch: x64
|
||||
|
||||
- name: Upload MAA win arm64
|
||||
uses: MirrorChyan/uploading-action@v1
|
||||
if: always()
|
||||
with:
|
||||
filetype: latest-release
|
||||
filename: "*MAA-*-win-arm64.zip"
|
||||
mirrorchyan_rid: MAA
|
||||
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
upload_token: ${{ secrets.MirrorChyanUploadToken }}
|
||||
os: win
|
||||
arch: arm64
|
||||
|
||||
- name: Upload MAA macos arm64
|
||||
uses: MirrorChyan/uploading-action@v1
|
||||
if: always()
|
||||
with:
|
||||
filetype: latest-release
|
||||
filename: "MAA-*-macos-universal.dmg"
|
||||
extra_zip: true
|
||||
mirrorchyan_rid: MAA
|
||||
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
upload_token: ${{ secrets.MirrorChyanUploadToken }}
|
||||
os: macos
|
||||
arch: arm64
|
||||
|
||||
- name: Upload MAA macos x64
|
||||
uses: MirrorChyan/uploading-action@v1
|
||||
if: always()
|
||||
with:
|
||||
filetype: latest-release
|
||||
filename: "MAA-*-macos-universal.dmg"
|
||||
extra_zip: true
|
||||
mirrorchyan_rid: MAA
|
||||
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
upload_token: ${{ secrets.MirrorChyanUploadToken }}
|
||||
os: macos
|
||||
arch: x64
|
||||
@@ -1,4 +1,5 @@
|
||||
name: Release Note Distribution
|
||||
name: mirrorchyan_release_note
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
@@ -6,11 +7,10 @@ on:
|
||||
|
||||
jobs:
|
||||
mirrorchyan:
|
||||
name: Upload to MirrorChyan
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- name: Upload release notes to MirrorChyan
|
||||
- name: Release Note for MAA
|
||||
uses: MirrorChyan/release-note-action@v1
|
||||
with:
|
||||
mirrorchyan_rid: MAA
|
||||
|
||||
25
.github/workflows/optimize-templates.yml
vendored
25
.github/workflows/optimize-templates.yml
vendored
@@ -1,12 +1,14 @@
|
||||
name: PNG Image Optimization
|
||||
name: Optimize PNG Templates
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "dev"
|
||||
paths:
|
||||
- "docs/.vuepress/public/images/**"
|
||||
- "resource/**/*.png"
|
||||
- "docs/.vuepress/public/images/**"
|
||||
- "website/apps/web/public/**"
|
||||
- "website/apps/web/src/assets/links/**"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
commit_message:
|
||||
@@ -16,21 +18,19 @@ on:
|
||||
|
||||
jobs:
|
||||
optimize-png:
|
||||
name: Optimize PNG Images
|
||||
# Skip workflow to prevent double consecutive runs
|
||||
if: github.repository_owner == 'MaaAssistantArknights' && github.event.head_commit.author.email != '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
# Skip workflow on PR merges
|
||||
if: github.repository_owner == 'MaaAssistantArknights' && ${{ github.event.head_commit.author.email != '41898282+github-actions[bot]@users.noreply.github.com' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Skip workflow on PR merges
|
||||
- name: Check if it is a direct push
|
||||
- name: Check for direct push
|
||||
id: check_push
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" != "workflow_dispatch" ]]; then
|
||||
pr_count=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/commits/${{ github.event.after }}/pulls" \
|
||||
| jq 'length')
|
||||
pr_merge_status=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/commits/${{ github.event.after }}/pulls" | xargs)
|
||||
|
||||
if [[ "$pr_count" == "0" ]]; then
|
||||
if [[ "$pr_merge_status" == "[ ]" ]]; then
|
||||
echo "Direct push detected. Proceeding..."
|
||||
echo "is_pr=False" >> $GITHUB_OUTPUT
|
||||
else
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
- name: Checkout repository
|
||||
if: steps.check_push.outputs.is_pr != 'True'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
persist-credentials: false
|
||||
@@ -59,7 +59,6 @@ jobs:
|
||||
# id: cache_python
|
||||
# if: steps.check_push.outputs.is_pr != 'True' && always()
|
||||
# uses: actions/cache@v4
|
||||
# continue-on-error: true
|
||||
# with:
|
||||
# path: ${{ env.pythonLocation }}/lib/python3.11/site-packages
|
||||
# key: ${{ runner.os }}-pip-optimize-templates-${{ hashFiles('./tools/OptimizeTemplates/requirements.txt') }}
|
||||
@@ -76,7 +75,7 @@ jobs:
|
||||
with:
|
||||
crate: oxipng
|
||||
|
||||
- name: Optimize png images
|
||||
- name: Run optimize_templates
|
||||
if: steps.check_push.outputs.is_pr != 'True'
|
||||
run: |
|
||||
python3 tools/OptimizeTemplates/optimize_templates.py
|
||||
|
||||
15
.github/workflows/pr-auto-tag.yml
vendored
15
.github/workflows/pr-auto-tag.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Release Version Tagging
|
||||
name: Auto Tag Release PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -15,23 +15,22 @@ on:
|
||||
|
||||
jobs:
|
||||
auto_tag_release:
|
||||
name: Tag Release
|
||||
if: github.event.pull_request.merged == true && (startsWith(github.event.pull_request.title, 'Release v') || startsWith(github.event.pull_request.title, 'release v')) || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.MAARELEASE_RELEASE }}
|
||||
|
||||
- name: Configure git
|
||||
- name: Git config
|
||||
run: |
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Determine tag name
|
||||
- name: Extract tag name
|
||||
id: extract_tag
|
||||
run: |
|
||||
if ${{ github.event_name != 'workflow_dispatch' }}; then
|
||||
@@ -41,12 +40,12 @@ jobs:
|
||||
echo "tag_name=${{ inputs.tag }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Create and push release tag
|
||||
- name: Create release tag and push
|
||||
run: |
|
||||
git tag -a "${{ steps.extract_tag.outputs.tag_name }}" -m "${{ steps.extract_tag.outputs.tag_name }}" -f
|
||||
git push origin "${{ steps.extract_tag.outputs.tag_name }}"
|
||||
|
||||
- name: Merge tag into dev and push
|
||||
- name: Merge into dev and push
|
||||
run: |
|
||||
git switch dev
|
||||
git merge "${{ steps.extract_tag.outputs.tag_name }}"
|
||||
|
||||
7
.github/workflows/pr-checker.yml
vendored
7
.github/workflows/pr-checker.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: PR Commit Check
|
||||
name: PR Checker
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
@@ -6,11 +6,10 @@ on:
|
||||
|
||||
jobs:
|
||||
check_commit_name_in_pr:
|
||||
name: Check Commits in PR
|
||||
if: ${{ !github.event.pull_request.merged && github.base_ref != 'master' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clean up previous comment
|
||||
- name: Cleanup Previous Comment
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
@@ -28,7 +27,7 @@ jobs:
|
||||
comment_id: previousComment.id
|
||||
});
|
||||
}
|
||||
- name: Check commits
|
||||
- name: Check Commits
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
|
||||
36
.github/workflows/pre-commit-scheduled.yml
vendored
36
.github/workflows/pre-commit-scheduled.yml
vendored
@@ -1,36 +0,0 @@
|
||||
name: Scheduled Pre-commit
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 每天 UTC 21:00 运行(北京时间 5:00)
|
||||
- cron: "0 21 * * *"
|
||||
workflow_dispatch: # 允许手动触发
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
show-progress: false
|
||||
|
||||
- name: Setup and run Prek
|
||||
uses: j178/prek-action@v1
|
||||
id: pre-commit
|
||||
continue-on-error: true
|
||||
with:
|
||||
extra-args: '--all-files'
|
||||
|
||||
- name: Commit and push changes
|
||||
if: steps.pre-commit.outcome == 'failure' && github.repository_owner == 'MaaAssistantArknights'
|
||||
uses: actions-js/push@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
message: "chore: Auto update by pre-commit hooks
|
||||
|
||||
https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
|
||||
[skip changelog]"
|
||||
branch: ${{ github.ref }}
|
||||
87
.github/workflows/release-nightly-ota.yml
vendored
87
.github/workflows/release-nightly-ota.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Release Pipeline (Nightly OTA)
|
||||
name: release-nightly-ota
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -26,7 +26,6 @@ on:
|
||||
|
||||
jobs:
|
||||
build-win-nightly:
|
||||
name: Build Nightly for Windows
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
@@ -39,8 +38,7 @@ jobs:
|
||||
main_tag_name: ${{ steps.push_main_tag.outputs.main_tag_name }}
|
||||
changelog: ${{ steps.read_changelog.outputs.content }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
# repository: 'MaaAssistantArknights/MaaAssistantArknights'
|
||||
#ref: ${{ inputs.ref }}
|
||||
@@ -53,7 +51,6 @@ jobs:
|
||||
|
||||
- name: Fetch submodules
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaUtils
|
||||
git submodule update --init --depth 1 3rdparty/EmulatorExtras
|
||||
|
||||
- name: Checkout ref (if provided)
|
||||
@@ -141,7 +138,7 @@ jobs:
|
||||
|
||||
gh run watch ${{ github.run_id }}
|
||||
|
||||
- name: Generate changelog
|
||||
- name: Generate Changelog
|
||||
id: generate_changelog
|
||||
run: |
|
||||
python3 tools/ChangelogGenerator/changelog_generator.py --latest "${{ steps.set_tag.outputs.latest_tag }}" --tag "${{ steps.set_tag.outputs.tag }}"
|
||||
@@ -163,7 +160,7 @@ jobs:
|
||||
|
||||
gh run watch ${{ github.run_id }}
|
||||
|
||||
- name: Read changelog to variable
|
||||
- name: Read Changelog to variable
|
||||
id: read_changelog
|
||||
uses: juliangruber/read-file-action@v1
|
||||
with:
|
||||
@@ -171,11 +168,10 @@ jobs:
|
||||
|
||||
- name: Cache MaaDeps
|
||||
id: cache-maadeps
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
./src/MaaUtils/MaaDeps
|
||||
./MaaDeps
|
||||
key: ${{ runner.os }}-${{ matrix.arch }}-maadeps-${{ hashFiles('tools/maadeps-download.py') }}
|
||||
|
||||
- name: Bootstrap MaaDeps
|
||||
@@ -185,31 +181,23 @@ jobs:
|
||||
run: |
|
||||
python3 tools/maadeps-download.py ${{ matrix.arch }}-windows
|
||||
|
||||
- name: Configure, build and install
|
||||
- name: Config cmake
|
||||
run: |
|
||||
cmake -B build --preset ${{ matrix.arch == 'arm64' && 'windows-publish-arm64' || 'windows-publish-x64' }} -DMAA_HASH_VERSION='${{ steps.set_tag.outputs.tag }}'
|
||||
cmake --build --preset ${{ matrix.arch == 'arm64' && 'windows-publish-arm64' || 'windows-publish-x64' }} --parallel $env:NUMBER_OF_PROCESSORS
|
||||
cmake --install build --config RelWithDebInfo
|
||||
mkdir -p build
|
||||
cmake -B build ${{ matrix.arch == 'arm64' && '-A ARM64' }} -DCMAKE_BUILD_TYPE=Release -DMAADEPS_TRIPLET='maa-${{ matrix.arch }}-windows' -DINSTALL_RESOURCE=ON -DINSTALL_PYTHON=ON -DMAA_HASH_VERSION='${{ steps.set_tag.outputs.tag }}' -DBUILD_WPF_GUI=OFF
|
||||
|
||||
- name: Download MaaFramework
|
||||
if: matrix.arch == 'x64'
|
||||
uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
repository: MaaXYZ/MaaFramework
|
||||
latest: true
|
||||
fileName: '*win-x86_64*.zip'
|
||||
extract: true
|
||||
out-file-path: MaaFramework-temp
|
||||
|
||||
- name: Copy MaaWin32ControlUnit
|
||||
if: matrix.arch == 'x64'
|
||||
- name: Build
|
||||
run: |
|
||||
cp MaaFramework-temp/bin/*Win32ControlUnit* install/
|
||||
cmake --build build --config Release --parallel $env:NUMBER_OF_PROCESSORS
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
mkdir -p install
|
||||
cmake --install build --prefix install --config Release
|
||||
|
||||
- name: Cache .nuke/temp, ~/.nuget/packages
|
||||
id: cache-nuget
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.nuke/temp
|
||||
@@ -220,7 +208,7 @@ jobs:
|
||||
if: steps.cache-nuget.outputs.cache-hit != 'true'
|
||||
run: dotnet restore src/MaaWpfGui/MaaWpfGui.csproj
|
||||
|
||||
- name: Taggify version for csproj
|
||||
- name: Taggify Version for csproj
|
||||
run: |
|
||||
$csprojPath = "src/MaaWpfGui/MaaWpfGui.csproj"
|
||||
$csprojPath = Resolve-Path -Path $csprojPath
|
||||
@@ -240,32 +228,19 @@ jobs:
|
||||
|
||||
- name: Publish WPF GUI
|
||||
run: |
|
||||
dotnet publish src/MaaWpfGui/MaaWpfGui.csproj -c Release -p:Platform=${{ matrix.arch == 'arm64' && 'ARM64' || 'x64' }} -o install
|
||||
dotnet publish src/MaaWpfGui/MaaWpfGui.csproj -c Release -o install
|
||||
|
||||
- name: Collect PDB files
|
||||
run: |
|
||||
cp build/bin/RelWithDebInfo/*.pdb install/
|
||||
Compress-Archive -Path install/*.pdb -DestinationPath install/MAAComponent-DebugSymbol-${{ steps.set_tag.outputs.tag }}-win-${{ matrix.arch }}.zip
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload PDB files
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: MAAComponent-DebugSymbol-win-${{ matrix.arch }}
|
||||
path: install/MAAComponent-DebugSymbol-${{ steps.set_tag.outputs.tag }}-win-${{ matrix.arch }}.zip
|
||||
|
||||
- name: Organize install files
|
||||
- name: Organize Install Files
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf install/MAAComponent-DebugSymbol-*.zip
|
||||
rm -rf install/*.pdb
|
||||
rm -rf install/msvc-debug
|
||||
rm -rf install/*.h
|
||||
|
||||
cp tools/DependencySetup_依赖库安装.bat install
|
||||
|
||||
- name: Upload MAA to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload MAA to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MAA-win-${{ matrix.arch }}
|
||||
path: install
|
||||
@@ -282,13 +257,12 @@ jobs:
|
||||
echo "main_tag_name=$main_tag_name" >> $env:GITHUB_OUTPUT
|
||||
|
||||
push-tag:
|
||||
name: Push Tag to MaaRelease
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
needs: build-win-nightly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout MaaRelease
|
||||
uses: actions/checkout@v6
|
||||
- name: Fetch MaaRelease
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: ${{ format('{0}/{1}', github.repository_owner, 'MaaRelease') }}
|
||||
fetch-depth: 0
|
||||
@@ -306,7 +280,6 @@ jobs:
|
||||
git push --tags origin HEAD:refs/tags/${{ needs.build-win-nightly.outputs.tag }}
|
||||
|
||||
make-ota:
|
||||
name: Build and Upload Nightly OTA for Windows
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
needs: [build-win-nightly, push-tag]
|
||||
strategy:
|
||||
@@ -314,24 +287,24 @@ jobs:
|
||||
target: [x64]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Show tag version
|
||||
- name: Echo tag version
|
||||
run: |
|
||||
echo ${{ needs.build-win-nightly.outputs.tag }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
path: MaaAssistantArknights
|
||||
token: ${{ secrets.MAARELEASE_RELEASE }}
|
||||
show-progress: false
|
||||
|
||||
- name: Download MAA from GitHub
|
||||
uses: actions/download-artifact@v7
|
||||
- name: Download MAA from Github
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: MAA-win-${{ matrix.target }}
|
||||
path: ${{ format('{0}/{1}', 'build-ota', needs.build-win-nightly.outputs.tag) }}
|
||||
|
||||
- name: Fetch release information
|
||||
- name: Fetch release info
|
||||
run: |
|
||||
mkdir -pv build-ota && cd build-ota
|
||||
|
||||
|
||||
40
.github/workflows/release-ota.yml
vendored
40
.github/workflows/release-ota.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Release Pipeline (OTA)
|
||||
name: release-ota
|
||||
|
||||
on:
|
||||
release:
|
||||
@@ -22,11 +22,10 @@ env:
|
||||
|
||||
jobs:
|
||||
create-tag:
|
||||
name: Create OTA Release Tag in MaaRelease
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout MaaRelease
|
||||
uses: actions/checkout@v6
|
||||
- name: Fetch MaaRelease
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
repository: ${{ format('{0}/{1}', github.repository_owner, 'MaaRelease') }}
|
||||
@@ -34,7 +33,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.MAARELEASE_RELEASE }}
|
||||
|
||||
- name: Fetch release information
|
||||
- name: Fetch release info
|
||||
id: fetchReleaseInfo
|
||||
run: |
|
||||
mkdir -pv build-ota && cd build-ota
|
||||
@@ -77,7 +76,7 @@ jobs:
|
||||
PUSH_REMOTE: https://github-actions[bot]:${{ secrets.MAARELEASE_RELEASE }}@github.com/${{ github.repository_owner }}/MaaRelease
|
||||
|
||||
- name: Upload release config to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MaaReleaseConfig
|
||||
path: ./build-ota/config
|
||||
@@ -87,7 +86,6 @@ jobs:
|
||||
release_tag: ${{ steps.fetchReleaseInfo.outputs.release_tag }}
|
||||
|
||||
make-ota:
|
||||
name: Build and Upload OTA for Windows
|
||||
needs: create-tag
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -96,13 +94,13 @@ jobs:
|
||||
- x64
|
||||
steps:
|
||||
- name: Download release config
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: MaaReleaseConfig
|
||||
path: ./MaaReleaseConfig
|
||||
|
||||
- name: Checkout MaaRelease
|
||||
uses: actions/checkout@v6
|
||||
- name: Fetch MaaRelease
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
repository: ${{ format('{0}/{1}', github.repository_owner, 'MaaRelease') }}
|
||||
@@ -110,8 +108,8 @@ jobs:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.MAARELEASE_RELEASE }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
path: MaaAssistantArknights
|
||||
@@ -139,21 +137,20 @@ jobs:
|
||||
prerelease: ${{ fromJSON(needs.create-tag.outputs.prerelease) }}
|
||||
overwrite: true
|
||||
|
||||
- name: Create issue on failure
|
||||
- name: Create issue if failed
|
||||
if: failure()
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: "create-issue"
|
||||
title: "Failed to make OTA release for Windows"
|
||||
title: "Failed make release OTA for Windows"
|
||||
body: |
|
||||
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
|
||||
make-ota-mac:
|
||||
name: Build and Upload OTA for macOS
|
||||
needs: create-tag
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: Fetch release information
|
||||
- name: Fetch release info
|
||||
run: gh release list --repo 'MaaAssistantArknights/MaaAssistantArknights' --limit ${{ inputs.limit || 31 }} | tee ./release_maa.txt
|
||||
|
||||
- name: Download release packages
|
||||
@@ -169,7 +166,7 @@ jobs:
|
||||
run: |
|
||||
gh release download --repo 'sparkle-project/Sparkle' --clobber -O - -p 'Sparkle-*.tar.xz' | tar xf -
|
||||
|
||||
- name: Generate update packages
|
||||
- name: Generate Update Packages
|
||||
run: |
|
||||
if [ $(head -n 1 release_maa.txt | awk '{ print $2 }') = 'Pre-release' ]; then
|
||||
echo ${{ secrets.SPARKLE_PRIV_KEY }} | ./bin/generate_appcast --channel beta --ed-key-file - ./packages
|
||||
@@ -177,7 +174,7 @@ jobs:
|
||||
echo ${{ secrets.SPARKLE_PRIV_KEY }} | ./bin/generate_appcast --ed-key-file - ./packages
|
||||
fi
|
||||
|
||||
- name: Clean up files
|
||||
- name: Cleanup files
|
||||
run: |
|
||||
find ./packages -type f ! \( -name 'MAA-${{ needs.create-tag.outputs.release_tag }}-macos-universal.dmg' -o -name '*.delta' -o -name '*.xml' \) -print -delete
|
||||
|
||||
@@ -192,17 +189,16 @@ jobs:
|
||||
prerelease: ${{ fromJSON(needs.create-tag.outputs.prerelease) }}
|
||||
overwrite: true
|
||||
|
||||
- name: Create issue on failure
|
||||
- name: Create issue if failed
|
||||
if: failure()
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: "create-issue"
|
||||
title: "Failed to make OTA release for macOS"
|
||||
title: "Failed make release OTA for macos"
|
||||
body: |
|
||||
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
|
||||
|
||||
release:
|
||||
name: Publish to Release Mirrors
|
||||
needs:
|
||||
- make-ota
|
||||
- make-ota-mac
|
||||
|
||||
154
.github/workflows/release-package-distribution.yml
vendored
154
.github/workflows/release-package-distribution.yml
vendored
@@ -1,154 +0,0 @@
|
||||
name: Release Package Distribution
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: "Release Tag (empty for latest)"
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
mirrorchyan:
|
||||
description: "Upload to MirrorChyan"
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
winget:
|
||||
description: "Upload to WinGet"
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
maa_cos:
|
||||
description: "Upload to MAA COS"
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
|
||||
env:
|
||||
RELEASE_TAG_RAW: ${{ github.event.inputs.release_tag || 'latest' }}
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
name: Define Release Tag
|
||||
if: ${{ github.repository_owner == 'MaaAssistantArknights' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
RELEASE_TAG: ${{ steps.define_release_tag.outputs.RELEASE_TAG }}
|
||||
|
||||
steps:
|
||||
- name: Get latest release tag
|
||||
id: get_latest
|
||||
if: ${{ env.RELEASE_TAG_RAW == 'latest' }}
|
||||
uses: pozetroninc/github-action-get-latest-release@master
|
||||
with:
|
||||
owner: ${{ github.repository_owner }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
excludes: "draft"
|
||||
|
||||
- name: Define release tag
|
||||
id: define_release_tag
|
||||
run: |
|
||||
if [ "${{ env.RELEASE_TAG_RAW }}" == "latest" ]; then
|
||||
echo "RELEASE_TAG=${{ steps.get_latest.outputs.release }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "RELEASE_TAG=${{ env.RELEASE_TAG_RAW }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
mirrorchyan:
|
||||
name: Upload to MirrorChyan
|
||||
needs: meta
|
||||
if: ${{ github.event.inputs.mirrorchyan == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: win
|
||||
arch: x64
|
||||
filename: "*MAA-*-win-x64.zip"
|
||||
extra_zip: false
|
||||
- os: win
|
||||
arch: arm64
|
||||
filename: "*MAA-*-win-arm64.zip"
|
||||
extra_zip: false
|
||||
- os: macos
|
||||
arch: arm64
|
||||
filename: "MAA-*-macos-universal.dmg"
|
||||
extra_zip: true
|
||||
- os: macos
|
||||
arch: x64
|
||||
filename: "MAA-*-macos-universal.dmg"
|
||||
extra_zip: true
|
||||
|
||||
env:
|
||||
RELEASE_TAG: ${{ needs.meta.outputs.RELEASE_TAG }}
|
||||
|
||||
steps:
|
||||
- name: Upload MAA ${{ matrix.os }} ${{ matrix.arch }}
|
||||
uses: MirrorChyan/uploading-action@v1
|
||||
continue-on-error: true
|
||||
with:
|
||||
filetype: latest-release
|
||||
filename: ${{ matrix.filename }}
|
||||
extra_zip: ${{ matrix.extra_zip }}
|
||||
tag: ${{ env.RELEASE_TAG }}
|
||||
mirrorchyan_rid: MAA
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repo: ${{ github.event.repository.name }}
|
||||
upload_token: ${{ secrets.MirrorChyanUploadToken }}
|
||||
os: ${{ matrix.os }}
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
winget:
|
||||
name: Upload to WinGet
|
||||
needs: meta
|
||||
if: ${{ github.event.inputs.winget == 'true' }}
|
||||
runs-on: windows-latest
|
||||
continue-on-error: true
|
||||
|
||||
env:
|
||||
RELEASE_TAG: ${{ needs.meta.outputs.RELEASE_TAG }}
|
||||
|
||||
steps:
|
||||
- name: Upload MAA to WinGet
|
||||
uses: vedantmgoyal9/winget-releaser@main
|
||||
with:
|
||||
identifier: MaaAssistantArknights.MaaAssistantArknights
|
||||
version: ""
|
||||
installers-regex: "-win-"
|
||||
max-versions-to-keep: 0
|
||||
release-tag: ${{ env.RELEASE_TAG }}
|
||||
fork-user: MaaAssistantArknights
|
||||
token: ${{ secrets.MAABOT_WINGET_TOKEN }}
|
||||
|
||||
maa_cos:
|
||||
name: Upload to MAA COS
|
||||
needs: meta
|
||||
if: ${{ github.event.inputs.maa_cos == 'true' && !contains(needs.meta.outputs.RELEASE_TAG, '-') }}
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
env:
|
||||
FILENAME: MAA-${{ needs.meta.outputs.RELEASE_TAG }}-win-x64.zip
|
||||
|
||||
steps:
|
||||
- uses: robinraju/release-downloader@v1
|
||||
with:
|
||||
repository: 'MaaAssistantArknights/MaaAssistantArknights'
|
||||
latest: true
|
||||
fileName: ${{ env.FILENAME }}
|
||||
out-file-path: 'downloads'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload to COS
|
||||
uses: zkqiang/tencent-cos-action@v0.1.0
|
||||
with:
|
||||
args: upload -rs downloads/${{ env.FILENAME }} MAA/${{ env.FILENAME }}
|
||||
secret_id: ${{ secrets.MISTEO_MAA_COS_SECRET_ID }}
|
||||
secret_key: ${{ secrets.MISTEO_MAA_COS_SECRET_KEY }}
|
||||
bucket: ${{ secrets.MISTEO_MAA_COS_BUCKET }}
|
||||
region: ${{ secrets.MISTEO_MAA_COS_REG }}
|
||||
203
.github/workflows/res-update-game.yml
vendored
203
.github/workflows/res-update-game.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Game Resource Update
|
||||
name: Resource Updater
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -12,12 +12,11 @@ on:
|
||||
|
||||
jobs:
|
||||
clone-resources-official:
|
||||
name: Download Official Resources
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone ArknightsGameResource for Official
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
repository: yuanyan3060/ArknightsGameResource
|
||||
@@ -36,20 +35,19 @@ jobs:
|
||||
/gamedata/excel/roguelike_topic_table.json
|
||||
/gamedata/excel/activity_table.json
|
||||
|
||||
- name: Upload Official resources
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload Official
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: official
|
||||
path: ./Official
|
||||
compression-level: 0
|
||||
|
||||
clone-resources-overseas:
|
||||
name: Download Overseas Resources
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone ArknightsGameResource_Yostar for Overseas
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
repository: ArknightsAssets/ArknightsGamedata
|
||||
@@ -79,25 +77,25 @@ jobs:
|
||||
/kr/gamedata/excel/roguelike_topic_table.json
|
||||
/kr/gamedata/excel/activity_table.json
|
||||
|
||||
- name: Upload Overseas resources
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload Official
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: overseas
|
||||
path: ./Overseas
|
||||
compression-level: 0
|
||||
|
||||
clone-resources-txwy:
|
||||
name: Download Taiwan Resources
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone arknights-toolbox-update for Taiwan
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
repository: arkntools/arknights-data-tw-for-maa
|
||||
ref: main
|
||||
repository: arkntools/arknights-toolbox-update
|
||||
ref: data-tw
|
||||
path: ./excel
|
||||
token: ${{ secrets.ARKNTOOLS_MAA_RESOURCE_UPDATER}}
|
||||
|
||||
- name: Download stages.json from Penguin Stats
|
||||
run: |
|
||||
@@ -107,45 +105,34 @@ jobs:
|
||||
|
||||
parameters=("CN" "US" "JP" "KR")
|
||||
|
||||
pids=()
|
||||
for param in "${parameters[@]}"; do
|
||||
{
|
||||
if curl -f -s -o "stages_${param}.json" "${baseUrl}${param}"; then
|
||||
if curl -s -o "stages_${param}.json" "${baseUrl}${param}"; then
|
||||
echo "Successfully fetched data for ${param}"
|
||||
else
|
||||
echo "Failed to fetch data for ${param}" >&2
|
||||
exit 1
|
||||
fi
|
||||
} &
|
||||
pids+=($!)
|
||||
done
|
||||
wait
|
||||
|
||||
failed=0
|
||||
for pid in "${pids[@]}"; do
|
||||
if ! wait "$pid"; then
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $failed -ne 0 ]; then
|
||||
echo "One or more downloads failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload Taiwan resources
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload Official
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: txwy
|
||||
path: ./excel
|
||||
compression-level: 0
|
||||
|
||||
update-game-resources:
|
||||
name: Update Game Resources
|
||||
# In case of rate limitations on the runners/instances, add dependency, by removing the comment
|
||||
|
||||
# needs: [clone-resources-official, clone-resources-overseas, clone-resources-txwy]
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout MAA
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# TL;DR https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/9872#issuecomment-2251378371
|
||||
# actions/checkout uses ${{ secrets.GITHUB_TOKEN }} by default, meaning all steps will inherit it
|
||||
@@ -153,14 +140,9 @@ jobs:
|
||||
show-progress: false
|
||||
fetch-depth: 3
|
||||
|
||||
- name: Fetch submodules
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaUtils
|
||||
|
||||
- name: Restore ResourceUpdater from cache
|
||||
id: resupd-cache
|
||||
uses: actions/cache/restore@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
key: ResourceUpdater-${{ runner.os }}-${{ hashFiles('tools/ResourceUpdater/main.cpp') }}
|
||||
path: |
|
||||
@@ -170,11 +152,10 @@ jobs:
|
||||
- name: Cache MaaDeps
|
||||
if: steps.resupd-cache.outputs.cache-hit != 'true'
|
||||
id: maadeps-cache
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
./src/MaaUtils/MaaDeps
|
||||
./MaaDeps
|
||||
key: ${{ runner.os }}-arm64-maadeps-${{ hashFiles('tools/maadeps-download.py') }}
|
||||
|
||||
- name: Bootstrap MaaDeps
|
||||
@@ -184,57 +165,100 @@ jobs:
|
||||
run: |
|
||||
python3 tools/maadeps-download.py arm64-osx
|
||||
|
||||
- name: Config, Build & Install ResourceUpdater
|
||||
- name: Config cmake
|
||||
if: steps.resupd-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd tools/ResourceUpdater
|
||||
cmake --preset res-updater-macos-arm64
|
||||
cmake --build --preset res-updater-macos-arm64 --parallel $(sysctl -n hw.logicalcpu)
|
||||
cmake --install build --config Release
|
||||
mkdir -p build
|
||||
cmake -B build -GNinja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DMAADEPS_TRIPLET='maa-arm64-osx' \
|
||||
-DWITH_HASH_VERSION=ON
|
||||
|
||||
- name: Build
|
||||
if: steps.resupd-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cmake --build tools/ResourceUpdater/build --config Release --parallel $(sysctl -n hw.logicalcpu)
|
||||
|
||||
- name: Install
|
||||
if: steps.resupd-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cmake --install tools/ResourceUpdater/build --prefix tools/ResourceUpdater --config Release
|
||||
|
||||
- name: Save ResourceUpdater to cache
|
||||
if: always() && steps.resupd-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
key: ResourceUpdater-${{ runner.os }}-${{ hashFiles('tools/ResourceUpdater/main.cpp') }}
|
||||
path: |
|
||||
./tools/ResourceUpdater/libopencv_world4.4.11.0.dylib
|
||||
./tools/ResourceUpdater/res_updater
|
||||
|
||||
- name: Wait for resource cloning
|
||||
uses: yogeshlonkar/wait-for-jobs@v0
|
||||
with:
|
||||
ignore-skipped: 'false'
|
||||
jobs: |
|
||||
Download Official Resources
|
||||
Download Overseas Resources
|
||||
Download Taiwan Resources
|
||||
ttl: 15
|
||||
|
||||
- name: Download txwy
|
||||
uses: actions/download-artifact@v7
|
||||
id: download-txwy
|
||||
uses: actions/download-artifact@v5
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: txwy
|
||||
path: ./tools/ResourceUpdater/Overseas/tw/gamedata/excel
|
||||
|
||||
- name: Delay txwy
|
||||
if: steps.download-txwy.outcome == 'failure'
|
||||
run: |
|
||||
sleep 10
|
||||
|
||||
- name: Re-download txwy
|
||||
if: steps.download-txwy.outcome == 'failure'
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: txwy
|
||||
path: ./tools/ResourceUpdater/Overseas/tw/gamedata/excel
|
||||
|
||||
- name: Download Overseas
|
||||
uses: actions/download-artifact@v7
|
||||
id: download-overseas
|
||||
uses: actions/download-artifact@v5
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: overseas
|
||||
path: ./tools/ResourceUpdater/Overseas
|
||||
|
||||
- name: Delay Overseas
|
||||
if: steps.download-overseas.outcome == 'failure'
|
||||
run: |
|
||||
sleep 10
|
||||
|
||||
- name: Re-download Overseas
|
||||
if: steps.download-overseas.outcome == 'failure'
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: overseas
|
||||
path: ./tools/ResourceUpdater/Overseas
|
||||
|
||||
- name: Download Official
|
||||
uses: actions/download-artifact@v7
|
||||
id: download-official
|
||||
uses: actions/download-artifact@v5
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: official
|
||||
path: ./tools/ResourceUpdater/Official
|
||||
|
||||
- name: Update resources
|
||||
- name: Delay Official
|
||||
if: steps.download-official.outcome == 'failure'
|
||||
run: |
|
||||
sleep 10
|
||||
|
||||
- name: Re-download Official
|
||||
if: steps.download-official.outcome == 'failure'
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: official
|
||||
path: ./tools/ResourceUpdater/Official
|
||||
|
||||
- name: Run Resource Updater
|
||||
run: |
|
||||
./tools/ResourceUpdater/res_updater
|
||||
|
||||
- name: Sort tasks
|
||||
- name: Task Sorting
|
||||
id: task_sorting
|
||||
run: |
|
||||
python3 tools/TaskSorter/TaskSorter.py
|
||||
@@ -248,7 +272,7 @@ jobs:
|
||||
- name: Update version.json date if necessary
|
||||
id: update_version
|
||||
run: |
|
||||
sh ./tools/ResourceUpdater/version.sh
|
||||
./tools/ResourceUpdater/version.zsh
|
||||
|
||||
- name: Setup python
|
||||
if: steps.update_version.outputs.contains_png == 'True'
|
||||
@@ -256,11 +280,10 @@ jobs:
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Cache python packages
|
||||
- name: Cache Python packages
|
||||
if: always() && steps.update_version.outputs.contains_png == 'True'
|
||||
id: cache_python
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}/Lib/site-packages
|
||||
key: ${{ runner.os }}-pip-optimize-templates-${{ hashFiles('./tools/OptimizeTemplates/requirements.txt') }}
|
||||
@@ -276,12 +299,12 @@ jobs:
|
||||
with:
|
||||
crate: oxipng
|
||||
|
||||
- name: Optimize png images
|
||||
- name: Run optimize_templates
|
||||
if: steps.update_version.outputs.contains_png == 'True'
|
||||
run: |
|
||||
python3 tools/OptimizeTemplates/optimize_templates.py --no-cleanup -p resource/template/items/ resource/template/infrast/
|
||||
python3 tools/OptimizeTemplates/optimize_templates.py -p resource/template/items/ resource/template/infrast/
|
||||
|
||||
- name: Commit changes
|
||||
- name: Add files to git
|
||||
if: steps.update_version.outputs.changes == 'True'
|
||||
id: add_files
|
||||
run: |
|
||||
@@ -326,42 +349,4 @@ jobs:
|
||||
# - name: Release # ref: https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow
|
||||
# if: steps.add_files.outputs.have_commits == 'True'
|
||||
# run: |
|
||||
# gh workflow run release-nightly-ota.yml -f release_body="Auto Release of Resource Updates"
|
||||
|
||||
- name: Upsert failure comment (single active)
|
||||
if: failure() && github.ref == 'refs/heads/dev'
|
||||
run: |
|
||||
run_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||
latest_id=$(gh api --paginate repos/${{ github.repository }}/issues/14493/comments | jq -r '.[] | select(.user.login=="github-actions[bot]") | .id' | tail -n 1)
|
||||
if [ -n "$latest_id" ]; then
|
||||
body=$(gh api repos/${{ github.repository }}/issues/comments/$latest_id --jq '.body')
|
||||
if echo "$body" | grep -q '/actions/runs/'; then
|
||||
# Count existing run URLs
|
||||
count=$(echo "$body" | grep -o 'https://github.com/[^[:space:]]*' | wc -l)
|
||||
# Collapse existing content
|
||||
old_content=$(echo "$body" | sed 's|https://github.com/[^[:space:]]*|<details>\n<summary>⚠️ Previous failures ('"$count"')</summary>\n\n###### &\n\n</details>|g')
|
||||
new_body="$run_url
|
||||
|
||||
@MistEO @ABA2396 @Constrat
|
||||
|
||||
$old_content"
|
||||
gh api repos/${{ github.repository }}/issues/comments/$latest_id -X PATCH -f body="$new_body" || echo "Patch failed"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
# Create new failure comment if none suitable
|
||||
gh issue comment 14493 -R ${{ github.repository }} --body "$run_url
|
||||
|
||||
@MistEO @ABA2396 @Constrat"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Minimize failure comment on success/cancelled
|
||||
if: ${{ !failure() && github.ref == 'refs/heads/dev' }}
|
||||
run: |
|
||||
latest_node=$(gh api --paginate repos/${{ github.repository }}/issues/14493/comments | jq -r '.[] | select(.user.login=="github-actions[bot]") | .node_id' | tail -n 1)
|
||||
if [ -n "$latest_node" ]; then
|
||||
gh api graphql -f query='mutation { minimizeComment(input: {subjectId: "'"$latest_node"'", classifier: OUTDATED}) { minimizedComment { isMinimized } } }' || true
|
||||
fi
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# gh workflow run release-nightly-ota -f release_body="Auto Release of Resource Updates"
|
||||
|
||||
87
.github/workflows/smoke-testing.yml
vendored
87
.github/workflows/smoke-testing.yml
vendored
@@ -1,69 +1,58 @@
|
||||
name: Smoke Test
|
||||
permissions:
|
||||
contents: read
|
||||
name: smoke-testing
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "dev"
|
||||
paths:
|
||||
- ".github/workflows/smoke-testing.yml"
|
||||
- "3rdparty/include/**"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- "include/**"
|
||||
- "resource/**"
|
||||
- "src/Cpp/**"
|
||||
- "src/MaaCore/**"
|
||||
- "tools/maadeps-download.py"
|
||||
- "tools/SmokeTesting/**"
|
||||
- "resource/**"
|
||||
- "!**/*.md"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- "tools/maadeps-download.py"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/smoke-testing.yml"
|
||||
- "3rdparty/include/**"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- "include/**"
|
||||
- "resource/**"
|
||||
- "src/Cpp/**"
|
||||
- "src/MaaCore/**"
|
||||
- "tools/maadeps-download.py"
|
||||
- "tools/SmokeTesting/**"
|
||||
- "resource/**"
|
||||
- "!**/*.md"
|
||||
- "cmake/**"
|
||||
- "CMakeLists.txt"
|
||||
- "tools/maadeps-download.py"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.head_ref || github.ref_name }}${{ github.ref == 'refs/heads/dev' && format('-{0}', github.sha) || '' }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
smoke-testing:
|
||||
name: Run Smoke Test
|
||||
# Prevent duplicate runs on organization branches with PRs
|
||||
if: github.event_name != 'pull_request' ||
|
||||
github.event.pull_request.head.repo.full_name !=
|
||||
github.event.pull_request.base.repo.full_name
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Generate cache key
|
||||
id: cache_key
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "key=Smoke-testing-${{ hashFiles('src/Cpp/**', 'src/MaaCore/**', '3rdparty/include/**', 'include/**', 'cmake/**', 'CMakeLists.txt', 'tools/maadeps-download.py', 'tools/linux-toolchain-download.py') }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Restore cache for Smoke Test
|
||||
if: ${{ steps.cache_key.outputs.key != '' }}
|
||||
- name: Restore cache smoke-testing
|
||||
id: smoke-cache
|
||||
uses: actions/cache/restore@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
key: ${{ steps.cache_key.outputs.key }}
|
||||
path: |
|
||||
./install/libfastdeploy_ppocr.dylib
|
||||
./install/libMaaCore.dylib
|
||||
./install/libMaaUtils.dylib
|
||||
./install/libonnxruntime.1.19.2.dylib
|
||||
./install/libopencv_world4.4.11.0.dylib
|
||||
./install/smoke_test
|
||||
@@ -71,15 +60,14 @@ jobs:
|
||||
- name: Fetch submodules
|
||||
if: steps.smoke-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaUtils
|
||||
git submodule update --init --depth 1 3rdparty/EmulatorExtras
|
||||
|
||||
- name: Cache MaaDeps
|
||||
if: steps.smoke-cache.outputs.cache-hit != 'true'
|
||||
id: maadeps-cache
|
||||
uses: actions/cache@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./src/MaaUtils/MaaDeps
|
||||
path: ./MaaDeps
|
||||
key: ${{ runner.os }}-arm64-maadeps-${{ hashFiles('tools/maadeps-download.py') }}
|
||||
|
||||
- name: Bootstrap MaaDeps
|
||||
@@ -89,39 +77,52 @@ jobs:
|
||||
run: |
|
||||
python3 tools/maadeps-download.py arm64-osx
|
||||
|
||||
- name: Configure, build and install
|
||||
- name: Config cmake
|
||||
if: steps.smoke-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cmake -B build --preset smoke-test
|
||||
cmake --build build --preset smoke-test --parallel $(sysctl -n hw.logicalcpu)
|
||||
cmake --install build --config Debug
|
||||
mkdir -p build
|
||||
cmake -B build -GNinja \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DMAADEPS_TRIPLET='maa-arm64-osx' \
|
||||
-DBUILD_SMOKE_TEST=ON \
|
||||
-DINSTALL_RESOURCE=ON \
|
||||
-DWITH_HASH_VERSION=ON
|
||||
|
||||
- name: Make link to Smoke Test cache
|
||||
- name: Build
|
||||
if: steps.smoke-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cmake --build build --config Debug --parallel $(sysctl -n hw.logicalcpu)
|
||||
|
||||
- name: Install
|
||||
if: steps.smoke-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p install
|
||||
cmake --install build --prefix install --config Debug
|
||||
|
||||
- name: Make link for cache smoke-testing
|
||||
if: steps.smoke-cache.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
ln -s "$(pwd)/resource" install/resource
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
sh ./tools/SmokeTesting/run_tests.sh
|
||||
./tools/SmokeTesting/run_tests.zsh
|
||||
|
||||
- name: Save cache for Smoke Test (only in dev)
|
||||
- name: Save cache smoke-testing (only in dev)
|
||||
if: steps.smoke-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/dev'
|
||||
uses: actions/cache/save@v5
|
||||
continue-on-error: true
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
key: ${{ steps.cache_key.outputs.key }}
|
||||
path: |
|
||||
./install/libfastdeploy_ppocr.dylib
|
||||
./install/libMaaCore.dylib
|
||||
./install/libMaaUtils.dylib
|
||||
./install/libonnxruntime.1.19.2.dylib
|
||||
./install/libopencv_world4.4.11.0.dylib
|
||||
./install/smoke_test
|
||||
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: logs
|
||||
path: ./install/debug
|
||||
|
||||
5
.github/workflows/stale.yml
vendored
5
.github/workflows/stale.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Issue Staleness Management
|
||||
name: "Inactive Issues Closer"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -11,7 +11,6 @@ env: # config
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: Handle Stale Issues
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
@@ -21,7 +20,7 @@ jobs:
|
||||
pull-requests: none
|
||||
contents: none
|
||||
steps:
|
||||
- name: Handle stale issues
|
||||
- name: Close inactive issues
|
||||
uses: actions/stale@v10
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
13
.github/workflows/sync-resource.yml
vendored
13
.github/workflows/sync-resource.yml
vendored
@@ -1,34 +1,33 @@
|
||||
name: Resource Sync
|
||||
name: sync-resource
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- ".github/workflows/sync-resource.yml"
|
||||
- "resource/**"
|
||||
- ".github/workflows/sync-resource.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
sync-resource:
|
||||
name: Sync Resource to MaaResource
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout MaaAssistantArknights
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Configure git
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git show -s
|
||||
|
||||
- name: Checkout MaaResource
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: MaaAssistantArknights/MaaResource
|
||||
show-progress: false
|
||||
|
||||
33
.github/workflows/update-submodules.yml
vendored
33
.github/workflows/update-submodules.yml
vendored
@@ -1,33 +0,0 @@
|
||||
name: Submodule Update
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "50 21 * * *" # Runs daily at 21:50 UTC (before `Release Pipeline (Nightly OTA)`)
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update-submodules:
|
||||
name: Update Submodules
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'MaaAssistantArknights'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Update submodules
|
||||
run: |
|
||||
git submodule update --remote src/MaaMacGui
|
||||
git submodule update --remote src/maa-cli
|
||||
|
||||
- name: Commit and push changes
|
||||
uses: actions-js/push@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
message: "feat: Update Submodules MaaMacGui, maa-cli
|
||||
|
||||
https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
|
||||
[skip changelog]"
|
||||
branch: ${{ github.ref }}
|
||||
31
.github/workflows/website-workflow.yml
vendored
31
.github/workflows/website-workflow.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Documentation Site
|
||||
name: MaaWebsite Workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -24,51 +24,48 @@ concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
# required for peaceiris/actions-gh-pages
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Deploy
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
package_json_file: "./docs/package.json"
|
||||
version: 10
|
||||
run_install: false
|
||||
|
||||
- name: Setup node.js environment
|
||||
uses: actions/setup-node@v6
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: pnpm
|
||||
cache-dependency-path: "./docs/pnpm-lock.yaml"
|
||||
|
||||
- name: Install node modules
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
working-directory: "./docs"
|
||||
|
||||
- name: Build
|
||||
- name: Build documentation
|
||||
run: pnpm run build
|
||||
working-directory: "./docs"
|
||||
|
||||
- name: Upload artifact to GitHub
|
||||
uses: actions/upload-artifact@v6
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
name: dist
|
||||
path: "./docs/.vuepress/dist"
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
if: github.repository_owner == 'MaaAssistantArknights' && (inputs.deploy-to-prod == true || github.ref == 'refs/heads/master')
|
||||
if: ${{ inputs.deploy-to-prod == true || github.ref == 'refs/heads/master' }}
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: "./docs/.vuepress/dist"
|
||||
|
||||
15
.gitignore
vendored
15
.gitignore
vendored
@@ -411,10 +411,10 @@ FodyWeavers.xsd
|
||||
# VS Code files for those working on multiple tools
|
||||
**/.vscode/*
|
||||
.vscode/*
|
||||
# !.vscode/settings.json
|
||||
# !.vscode/tasks.json
|
||||
# !.vscode/launch.json
|
||||
# !.vscode/extensions.json
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
@@ -434,6 +434,7 @@ FodyWeavers.xsd
|
||||
screen.png
|
||||
adb_screen.png
|
||||
tools/**/*.png
|
||||
.vscode
|
||||
enc_temp_folder/*
|
||||
|
||||
# RoguelikeRecruitmentTool 导出的 Excel 文件
|
||||
@@ -456,8 +457,7 @@ tools/RoguelikeRecruitmentTool/output
|
||||
.lycheecache
|
||||
|
||||
# MaaDeps
|
||||
MaaDeps
|
||||
src/MaaUtils/*
|
||||
/MaaDeps/*
|
||||
|
||||
# ResourceUpdater workflow
|
||||
/original/*
|
||||
@@ -478,6 +478,3 @@ install
|
||||
|
||||
# pnpm cache
|
||||
.pnpm-store
|
||||
|
||||
# CMake user presets
|
||||
CMakeUserPresets.json
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -10,6 +10,3 @@
|
||||
[submodule "3rdparty/EmulatorExtras"]
|
||||
path = 3rdparty/EmulatorExtras
|
||||
url = https://github.com/MaaXYZ/EmulatorExtras.git
|
||||
[submodule "src/MaaUtils"]
|
||||
path = src/MaaUtils
|
||||
url = https://github.com/MaaXYZ/MaaUtils
|
||||
|
||||
@@ -1,45 +1,39 @@
|
||||
default_install_hook_types: [pre-commit, prepare-commit-msg]
|
||||
ci:
|
||||
autofix_commit_msg: "chore: Auto update by pre-commit hooks [skip changelog]"
|
||||
autofix_prs: true
|
||||
repos:
|
||||
- repo: https://github.com/shssoichiro/oxipng
|
||||
rev: v10.0.0
|
||||
rev: v9.1.4
|
||||
hooks:
|
||||
- id: oxipng
|
||||
name: PNG Image Compression
|
||||
args: ["-q", "-o", "2", "-s", "--ng"]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v21.1.8
|
||||
rev: v20.1.0
|
||||
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.7.4
|
||||
rev: v3.5.3
|
||||
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
|
||||
- id: prettier
|
||||
name: Prettier (Documentation)
|
||||
files: ^docs/.*
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.14.10
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: v3.5.3
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
name: Ruff format (Python)
|
||||
|
||||
- id: prettier
|
||||
name: prettier (docs)
|
||||
files: ^docs/.*
|
||||
- repo: https://github.com/DavidAnson/markdownlint-cli2
|
||||
rev: v0.18.1
|
||||
rev: v0.17.2
|
||||
hooks:
|
||||
- id: markdownlint-cli2
|
||||
name: MarkdownLint (Documentation)
|
||||
files: ^docs/.*|^README\.md$
|
||||
types:
|
||||
- markdown
|
||||
args: ["--fix", "--config", "docs/.markdownlint.yaml"]
|
||||
args: ["--fix", "--config", "docs/.markdownlint.yaml", "#**/node_modules"]
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
**/node_modules/
|
||||
**/pnpm-lock.yaml
|
||||
docs/**/*.md
|
||||
|
||||
MaaDeps/
|
||||
3rdparty/
|
||||
src/maa-cli
|
||||
src/MaaMacGui
|
||||
src/MaaUtils
|
||||
|
||||
# website/
|
||||
# docs/
|
||||
|
||||
resource/Arknights-Tile-Pos/
|
||||
tools/OptimizeTemplates/optimize_templates.json
|
||||
|
||||
CITATION.cff
|
||||
CHANGELOG.md
|
||||
## FUCK FUCK
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -15,6 +15,5 @@
|
||||
"files.associations": {
|
||||
"**/resource/tasks/**/*.json": "jsonc"
|
||||
},
|
||||
"C_Cpp.exclusionPolicy": "checkFilesAndFolders",
|
||||
"cmake.outputLogEncoding": "UTF-8"
|
||||
"C_Cpp.exclusionPolicy": "checkFilesAndFolders"
|
||||
}
|
||||
|
||||
@@ -115,15 +115,15 @@ static constexpr double rel_pos_x = 1.3143386840820312;
|
||||
static constexpr double rel_pos_y = 1.314337134361267;
|
||||
static constexpr double rel_pos_z = -0.3967874050140381;
|
||||
|
||||
inline auto get_retreat_screen_pos(const Level& level, bool has_multi_stages = false)
|
||||
inline auto get_retreat_screen_pos(const Level& level)
|
||||
{
|
||||
const vec3d relative_pos = { -rel_pos_x + (has_multi_stages ? level.view[0].x : 0), +rel_pos_y, rel_pos_z };
|
||||
const vec3d relative_pos = { -rel_pos_x, +rel_pos_y, rel_pos_z };
|
||||
return world_to_screen(level, relative_pos, true);
|
||||
}
|
||||
|
||||
inline auto get_skill_screen_pos(const Level& level, bool has_multi_stages = false)
|
||||
inline auto get_skill_screen_pos(const Level& level)
|
||||
{
|
||||
const vec3d relative_pos = { +rel_pos_x + (has_multi_stages ? level.view[0].x : 0), -rel_pos_y, rel_pos_z };
|
||||
const vec3d relative_pos = { +rel_pos_x, -rel_pos_y, rel_pos_z };
|
||||
return world_to_screen(level, relative_pos, true);
|
||||
}
|
||||
|
||||
|
||||
688
3rdparty/include/meojson/common/array.hpp
vendored
Normal file
688
3rdparty/include/meojson/common/array.hpp
vendored
Normal file
@@ -0,0 +1,688 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace json
|
||||
{
|
||||
template <typename string_t>
|
||||
class basic_array
|
||||
{
|
||||
friend class basic_value<string_t>;
|
||||
friend class basic_object<string_t>;
|
||||
|
||||
public:
|
||||
using raw_array = std::vector<basic_value<string_t>>;
|
||||
using value_type = typename raw_array::value_type;
|
||||
using iterator = typename raw_array::iterator;
|
||||
using const_iterator = typename raw_array::const_iterator;
|
||||
using reverse_iterator = typename raw_array::reverse_iterator;
|
||||
using const_reverse_iterator = typename raw_array::const_reverse_iterator;
|
||||
using char_t = typename string_t::value_type;
|
||||
|
||||
public:
|
||||
basic_array() = default;
|
||||
basic_array(const basic_array<string_t>& rhs) = default;
|
||||
basic_array(basic_array<string_t>&& rhs) noexcept = default;
|
||||
basic_array(std::initializer_list<value_type> init_list);
|
||||
basic_array(typename raw_array::size_type size);
|
||||
|
||||
// explicit basic_array(const basic_value<string_t>& val);
|
||||
// explicit basic_array(basic_value<string_t>&& val);
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_to_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
basic_array(const jsonization_t& value)
|
||||
: basic_array(ext::jsonization<string_t, jsonization_t>().to_json(value))
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
basic_array(const jsonization_t& value)
|
||||
: basic_array(ext::jsonization<string_t, jsonization_t>().to_json_array(value))
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
std::is_rvalue_reference_v<jsonization_t&&>
|
||||
&& _utils::has_move_to_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_move_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
basic_array(jsonization_t&& value)
|
||||
: basic_array(ext::jsonization<string_t, jsonization_t>().move_to_json(std::move(value)))
|
||||
{
|
||||
}
|
||||
|
||||
//template <
|
||||
// typename jsonization_t,
|
||||
// std::enable_if_t<
|
||||
// std::is_rvalue_reference_v<jsonization_t&&>
|
||||
// && _utils::has_move_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
// bool> = true>
|
||||
//basic_array(jsonization_t&& value)
|
||||
// : basic_array(
|
||||
// ext::jsonization<string_t, jsonization_t>().move_to_json_array(std::move(value)))
|
||||
//{
|
||||
//}
|
||||
|
||||
~basic_array() noexcept = default;
|
||||
|
||||
bool empty() const noexcept { return _array_data.empty(); }
|
||||
|
||||
size_t size() const noexcept { return _array_data.size(); }
|
||||
|
||||
bool contains(size_t pos) const { return pos < _array_data.size(); }
|
||||
|
||||
bool exists(size_t pos) const { return contains(pos); }
|
||||
|
||||
const basic_value<string_t>& at(size_t pos) const;
|
||||
|
||||
string_t dumps(std::optional<size_t> indent = std::nullopt) const
|
||||
{
|
||||
return indent ? format(*indent) : to_string();
|
||||
}
|
||||
|
||||
string_t to_string() const;
|
||||
|
||||
string_t format(size_t indent = 4) const { return format(indent, 0); }
|
||||
|
||||
template <typename value_t>
|
||||
bool all() const;
|
||||
template <typename value_t, template <typename...> typename collection_t = std::vector>
|
||||
collection_t<value_t> as_collection() const;
|
||||
template <
|
||||
typename value_t,
|
||||
size_t Size,
|
||||
template <typename, size_t> typename fixed_array_t = std::array>
|
||||
fixed_array_t<value_t, Size> as_fixed_array() const;
|
||||
template <typename... elem_ts>
|
||||
std::tuple<elem_ts...> as_tuple() const;
|
||||
template <typename first_t, typename second_t>
|
||||
std::pair<first_t, second_t> as_pair() const;
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_from_json_array_in_templ_spec<value_t, string_t>::value,
|
||||
bool> = true>
|
||||
value_t as() const&
|
||||
{
|
||||
value_t res;
|
||||
ext::jsonization<string_t, value_t>().from_json_array(*this, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_move_from_json_array_in_templ_spec<value_t, string_t>::value,
|
||||
bool> = true>
|
||||
value_t as() &&
|
||||
{
|
||||
value_t res;
|
||||
ext::jsonization<string_t, value_t>().move_from_json_array(std::move(*this), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Usage: get(key_1, key_2, ..., default_value);
|
||||
template <typename... key_then_default_value_t>
|
||||
auto get(key_then_default_value_t&&... keys_then_default_value) const;
|
||||
|
||||
template <typename value_t = basic_value<string_t>>
|
||||
std::optional<value_t> find(size_t pos) const;
|
||||
|
||||
template <typename... args_t>
|
||||
decltype(auto) emplace_back(args_t&&... args);
|
||||
template <typename... args_t>
|
||||
decltype(auto) push_back(args_t&&... args);
|
||||
|
||||
void clear() noexcept;
|
||||
bool erase(size_t pos);
|
||||
bool erase(iterator iter);
|
||||
|
||||
iterator begin() noexcept;
|
||||
iterator end() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
reverse_iterator rbegin() noexcept;
|
||||
reverse_iterator rend() noexcept;
|
||||
const_reverse_iterator rbegin() const noexcept;
|
||||
const_reverse_iterator rend() const noexcept;
|
||||
const_reverse_iterator crbegin() const noexcept;
|
||||
const_reverse_iterator crend() const noexcept;
|
||||
|
||||
const basic_value<string_t>& operator[](size_t pos) const;
|
||||
basic_value<string_t>& operator[](size_t pos);
|
||||
|
||||
basic_array<string_t> operator+(const basic_array<string_t>& rhs) const&;
|
||||
basic_array<string_t> operator+(basic_array<string_t>&& rhs) const&;
|
||||
basic_array<string_t> operator+(const basic_array<string_t>& rhs) &&;
|
||||
basic_array<string_t> operator+(basic_array<string_t>&& rhs) &&;
|
||||
|
||||
basic_array<string_t>& operator+=(const basic_array<string_t>& rhs);
|
||||
basic_array<string_t>& operator+=(basic_array<string_t>&& rhs);
|
||||
|
||||
basic_array<string_t>& operator=(const basic_array<string_t>&) = default;
|
||||
basic_array<string_t>& operator=(basic_array<string_t>&&) noexcept = default;
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
std::enable_if_t<std::is_convertible_v<value_t, basic_array<string_t>>, bool> = true>
|
||||
basic_array<string_t>& operator=(value_t rhs)
|
||||
{
|
||||
return *this = basic_array<string_t>(std::move(rhs));
|
||||
}
|
||||
|
||||
bool operator==(const basic_array<string_t>& rhs) const;
|
||||
|
||||
bool operator!=(const basic_array<string_t>& rhs) const { return !(*this == rhs); }
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
template <typename...> typename collection_t = std::vector,
|
||||
std::enable_if_t<_utils::is_collection<collection_t<value_t>>, bool> = true>
|
||||
explicit operator collection_t<value_t>() const
|
||||
{
|
||||
return as_collection<value_t, collection_t>();
|
||||
}
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
size_t Size,
|
||||
template <typename, size_t> typename fixed_array_t = std::array,
|
||||
std::enable_if_t<_utils::is_fixed_array<fixed_array_t<value_t, Size>>, bool> = true>
|
||||
explicit operator fixed_array_t<value_t, Size>() const
|
||||
{
|
||||
return as<fixed_array_t<value_t, Size>>();
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() const&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().from_json(*this, dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() const&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().from_json_array(*this, dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_move_from_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_move_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() &&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().from_json(std::move(*this), dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_move_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() &&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().move_from_json_array(
|
||||
std::move(*this),
|
||||
dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... key_then_default_value_t, size_t... keys_indexes_t>
|
||||
auto
|
||||
get(std::tuple<key_then_default_value_t...> keys_then_default_value,
|
||||
std::index_sequence<keys_indexes_t...>) const;
|
||||
template <typename value_t, typename... rest_keys_t>
|
||||
auto get_helper(const value_t& default_value, size_t pos, rest_keys_t&&... rest) const;
|
||||
template <typename value_t>
|
||||
auto get_helper(const value_t& default_value, size_t pos) const;
|
||||
|
||||
string_t format(size_t indent, size_t indent_times) const;
|
||||
|
||||
private:
|
||||
raw_array _array_data;
|
||||
};
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t>::basic_array(std::initializer_list<value_type> init_list)
|
||||
: _array_data(init_list)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t>::basic_array(typename raw_array::size_type size)
|
||||
: _array_data(size)
|
||||
{
|
||||
}
|
||||
|
||||
// template <typename string_t>
|
||||
// inline basic_array<string_t>::basic_array(const basic_value<string_t>& val) :
|
||||
// basic_array<string_t>(val.as_array())
|
||||
//{}
|
||||
//
|
||||
// template <typename string_t>
|
||||
// inline basic_array<string_t>::basic_array(basic_value<string_t>&& val)
|
||||
// : basic_array<string_t>(std::move(val.as_array()))
|
||||
//{}
|
||||
|
||||
template <typename string_t>
|
||||
inline void basic_array<string_t>::clear() noexcept
|
||||
{
|
||||
_array_data.clear();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline bool basic_array<string_t>::erase(size_t pos)
|
||||
{
|
||||
return erase(_array_data.begin() + pos);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline bool basic_array<string_t>::erase(iterator iter)
|
||||
{
|
||||
return _array_data.erase(iter) != _array_data.end();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... args_t>
|
||||
inline decltype(auto) basic_array<string_t>::emplace_back(args_t&&... args)
|
||||
{
|
||||
static_assert(
|
||||
std::is_constructible_v<value_type, args_t...>,
|
||||
"Parameter can't be used to construct a raw_array::value_type");
|
||||
return _array_data.emplace_back(std::forward<args_t>(args)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... args_t>
|
||||
inline decltype(auto) basic_array<string_t>::push_back(args_t&&... args)
|
||||
{
|
||||
return emplace_back(std::forward<args_t>(args)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline const basic_value<string_t>& basic_array<string_t>::at(size_t pos) const
|
||||
{
|
||||
return _array_data.at(pos);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline string_t basic_array<string_t>::to_string() const
|
||||
{
|
||||
string_t str { '[' };
|
||||
for (auto iter = _array_data.cbegin(); iter != _array_data.cend();) {
|
||||
str += iter->to_string();
|
||||
if (++iter != _array_data.cend()) {
|
||||
str += ',';
|
||||
}
|
||||
}
|
||||
str += char_t(']');
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline string_t basic_array<string_t>::format(size_t indent, size_t indent_times) const
|
||||
{
|
||||
const string_t tail_indent(indent * indent_times, ' ');
|
||||
const string_t body_indent(indent * (indent_times + 1), ' ');
|
||||
|
||||
string_t str { '[', '\n' };
|
||||
for (auto iter = _array_data.cbegin(); iter != _array_data.cend();) {
|
||||
str += body_indent + iter->format(indent, indent_times + 1);
|
||||
if (++iter != _array_data.cend()) {
|
||||
str += ',';
|
||||
}
|
||||
str += '\n';
|
||||
}
|
||||
str += tail_indent + char_t(']');
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t>
|
||||
inline bool basic_array<string_t>::all() const
|
||||
{
|
||||
for (const auto& elem : _array_data) {
|
||||
if (!elem.template is<value_t>()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t, template <typename...> typename collection_t>
|
||||
inline collection_t<value_t> basic_array<string_t>::as_collection() const
|
||||
{
|
||||
return as<collection_t<value_t>>();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t, size_t Size, template <typename, size_t> typename fixed_array_t>
|
||||
inline fixed_array_t<value_t, Size> basic_array<string_t>::as_fixed_array() const
|
||||
{
|
||||
return as<fixed_array_t<value_t, Size>>();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... elem_ts>
|
||||
inline std::tuple<elem_ts...> basic_array<string_t>::as_tuple() const
|
||||
{
|
||||
return as<std::tuple<elem_ts...>>();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename first_t, typename second_t>
|
||||
inline std::pair<first_t, second_t> basic_array<string_t>::as_pair() const
|
||||
{
|
||||
return as<std::pair<first_t, second_t>>();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... key_then_default_value_t>
|
||||
inline auto basic_array<string_t>::get(key_then_default_value_t&&... keys_then_default_value) const
|
||||
{
|
||||
return get(
|
||||
std::forward_as_tuple(keys_then_default_value...),
|
||||
std::make_index_sequence<sizeof...(keys_then_default_value) - 1> {});
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... key_then_default_value_t, size_t... keys_indexes_t>
|
||||
inline auto basic_array<string_t>::get(
|
||||
std::tuple<key_then_default_value_t...> keys_then_default_value,
|
||||
std::index_sequence<keys_indexes_t...>) const
|
||||
{
|
||||
constexpr unsigned long default_value_index = sizeof...(key_then_default_value_t) - 1;
|
||||
return get_helper(
|
||||
std::get<default_value_index>(keys_then_default_value),
|
||||
std::get<keys_indexes_t>(keys_then_default_value)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t, typename... rest_keys_t>
|
||||
inline auto basic_array<string_t>::get_helper(
|
||||
const value_t& default_value,
|
||||
size_t pos,
|
||||
rest_keys_t&&... rest) const
|
||||
{
|
||||
constexpr bool is_json = std::is_same_v<basic_value<string_t>, value_t>
|
||||
|| std::is_same_v<basic_array<string_t>, value_t>
|
||||
|| std::is_same_v<basic_object<string_t>, value_t>;
|
||||
constexpr bool is_string = std::is_constructible_v<string_t, value_t> && !is_json;
|
||||
|
||||
if (!contains(pos)) {
|
||||
if constexpr (is_string) {
|
||||
return string_t(default_value);
|
||||
}
|
||||
else {
|
||||
return value_t(default_value);
|
||||
}
|
||||
}
|
||||
|
||||
return at(pos).get_helper(default_value, std::forward<rest_keys_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t>
|
||||
inline auto basic_array<string_t>::get_helper(const value_t& default_value, size_t pos) const
|
||||
{
|
||||
constexpr bool is_json = std::is_same_v<basic_value<string_t>, value_t>
|
||||
|| std::is_same_v<basic_array<string_t>, value_t>
|
||||
|| std::is_same_v<basic_object<string_t>, value_t>;
|
||||
constexpr bool is_string = std::is_constructible_v<string_t, value_t> && !is_json;
|
||||
|
||||
if (!contains(pos)) {
|
||||
if constexpr (is_string) {
|
||||
return string_t(default_value);
|
||||
}
|
||||
else {
|
||||
return value_t(default_value);
|
||||
}
|
||||
}
|
||||
|
||||
auto val = _array_data.at(pos);
|
||||
if (val.template is<value_t>()) {
|
||||
if constexpr (is_string) {
|
||||
return val.template as<string_t>();
|
||||
}
|
||||
else {
|
||||
return val.template as<value_t>();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr (is_string) {
|
||||
return string_t(default_value);
|
||||
}
|
||||
else {
|
||||
return value_t(default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t>
|
||||
inline std::optional<value_t> basic_array<string_t>::find(size_t pos) const
|
||||
{
|
||||
if (!contains(pos)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto& val = _array_data.at(pos);
|
||||
return val.template is<value_t>() ? std::optional<value_t>(val.template as<value_t>())
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::iterator basic_array<string_t>::begin() noexcept
|
||||
{
|
||||
return _array_data.begin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::iterator basic_array<string_t>::end() noexcept
|
||||
{
|
||||
return _array_data.end();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::begin() const noexcept
|
||||
{
|
||||
return _array_data.begin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::end() const noexcept
|
||||
{
|
||||
return _array_data.end();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::cbegin() const noexcept
|
||||
{
|
||||
return _array_data.cbegin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::cend() const noexcept
|
||||
{
|
||||
return _array_data.cend();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::reverse_iterator basic_array<string_t>::rbegin() noexcept
|
||||
{
|
||||
return _array_data.rbegin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::reverse_iterator basic_array<string_t>::rend() noexcept
|
||||
{
|
||||
return _array_data.rend();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_reverse_iterator
|
||||
basic_array<string_t>::rbegin() const noexcept
|
||||
{
|
||||
return _array_data.rbegin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_reverse_iterator
|
||||
basic_array<string_t>::rend() const noexcept
|
||||
{
|
||||
return _array_data.rend();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_reverse_iterator
|
||||
basic_array<string_t>::crbegin() const noexcept
|
||||
{
|
||||
return _array_data.crbegin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_array<string_t>::const_reverse_iterator
|
||||
basic_array<string_t>::crend() const noexcept
|
||||
{
|
||||
return _array_data.crend();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_value<string_t>& basic_array<string_t>::operator[](size_t pos)
|
||||
{
|
||||
return _array_data[pos];
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline const basic_value<string_t>& basic_array<string_t>::operator[](size_t pos) const
|
||||
{
|
||||
return _array_data[pos];
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t>
|
||||
basic_array<string_t>::operator+(const basic_array<string_t>& rhs) const&
|
||||
{
|
||||
basic_array<string_t> temp = *this;
|
||||
temp._array_data.insert(_array_data.end(), rhs.begin(), rhs.end());
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t> basic_array<string_t>::operator+(basic_array<string_t>&& rhs) const&
|
||||
{
|
||||
basic_array<string_t> temp = *this;
|
||||
temp._array_data.insert(
|
||||
_array_data.end(),
|
||||
std::make_move_iterator(rhs.begin()),
|
||||
std::make_move_iterator(rhs.end()));
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t> basic_array<string_t>::operator+(const basic_array<string_t>& rhs) &&
|
||||
{
|
||||
_array_data.insert(_array_data.end(), rhs.begin(), rhs.end());
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t> basic_array<string_t>::operator+(basic_array<string_t>&& rhs) &&
|
||||
{
|
||||
_array_data.insert(
|
||||
_array_data.end(),
|
||||
std::make_move_iterator(rhs.begin()),
|
||||
std::make_move_iterator(rhs.end()));
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t>& basic_array<string_t>::operator+=(const basic_array<string_t>& rhs)
|
||||
{
|
||||
_array_data.insert(_array_data.end(), rhs.begin(), rhs.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_array<string_t>& basic_array<string_t>::operator+=(basic_array<string_t>&& rhs)
|
||||
{
|
||||
_array_data.insert(
|
||||
_array_data.end(),
|
||||
std::make_move_iterator(rhs.begin()),
|
||||
std::make_move_iterator(rhs.end()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline bool basic_array<string_t>::operator==(const basic_array<string_t>& rhs) const
|
||||
{
|
||||
return _array_data == rhs._array_data;
|
||||
}
|
||||
|
||||
template <
|
||||
typename ostream_t,
|
||||
typename string_t,
|
||||
typename std_ostream_t = std::basic_ostream<
|
||||
typename string_t::value_type,
|
||||
std::char_traits<typename string_t::value_type>>,
|
||||
typename enable_t = std::enable_if_t<
|
||||
std::is_same_v<std_ostream_t, ostream_t> || std::is_base_of_v<std_ostream_t, ostream_t>>>
|
||||
ostream_t& operator<<(ostream_t& out, const basic_array<string_t>& arr)
|
||||
{
|
||||
out << arr.format();
|
||||
return out;
|
||||
}
|
||||
} // namespace json
|
||||
35
3rdparty/include/meojson/common/exception.hpp
vendored
Normal file
35
3rdparty/include/meojson/common/exception.hpp
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace json
|
||||
{
|
||||
class exception : public std::exception
|
||||
{
|
||||
public:
|
||||
exception() = default;
|
||||
|
||||
exception(const std::string& msg)
|
||||
: _what(msg)
|
||||
{
|
||||
}
|
||||
|
||||
exception(const exception&) = default;
|
||||
exception& operator=(const exception&) = default;
|
||||
exception(exception&&) = default;
|
||||
exception& operator=(exception&&) = default;
|
||||
|
||||
virtual ~exception() noexcept override = default;
|
||||
|
||||
virtual const char* what() const noexcept override
|
||||
{
|
||||
return _what.empty() ? "Unknown exception" : _what.c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string _what;
|
||||
};
|
||||
}
|
||||
605
3rdparty/include/meojson/common/object.hpp
vendored
Normal file
605
3rdparty/include/meojson/common/object.hpp
vendored
Normal file
@@ -0,0 +1,605 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace json
|
||||
{
|
||||
template <typename string_t>
|
||||
class basic_object
|
||||
{
|
||||
friend class basic_value<string_t>;
|
||||
friend class basic_array<string_t>;
|
||||
|
||||
public:
|
||||
using raw_object = std::map<string_t, basic_value<string_t>>;
|
||||
using key_type = typename raw_object::key_type;
|
||||
using mapped_type = typename raw_object::mapped_type;
|
||||
using value_type = typename raw_object::value_type;
|
||||
using iterator = typename raw_object::iterator;
|
||||
using const_iterator = typename raw_object::const_iterator;
|
||||
using char_t = typename string_t::value_type;
|
||||
|
||||
public:
|
||||
basic_object() = default;
|
||||
basic_object(const basic_object<string_t>& rhs) = default;
|
||||
basic_object(basic_object<string_t>&& rhs) noexcept = default;
|
||||
basic_object(std::initializer_list<value_type> init_list);
|
||||
|
||||
// explicit basic_object(const basic_value<string_t>& val);
|
||||
// explicit basic_object(basic_value<string_t>&& val);
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_to_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
basic_object(const jsonization_t& value)
|
||||
: basic_object(ext::jsonization<string_t, jsonization_t>().to_json(value))
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
basic_object(const jsonization_t& value)
|
||||
: basic_object(ext::jsonization<string_t, jsonization_t>().to_json_object(value))
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
std::is_rvalue_reference_v<jsonization_t&&>
|
||||
&& _utils::has_move_to_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_move_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
basic_object(jsonization_t&& value)
|
||||
: basic_object(ext::jsonization<string_t, jsonization_t>().move_to_json(std::move(value)))
|
||||
{
|
||||
}
|
||||
|
||||
//template <
|
||||
// typename jsonization_t,
|
||||
// std::enable_if_t<
|
||||
// std::is_rvalue_reference_v<jsonization_t&&>
|
||||
// && _utils::has_move_to_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
// bool> = true>
|
||||
//basic_object(jsonization_t&& value)
|
||||
// : basic_object(
|
||||
// ext::jsonization<string_t, jsonization_t>().move_to_json_object(std::move(value)))
|
||||
//{
|
||||
//}
|
||||
|
||||
~basic_object() = default;
|
||||
|
||||
bool empty() const noexcept { return _object_data.empty(); }
|
||||
|
||||
size_t size() const noexcept { return _object_data.size(); }
|
||||
|
||||
bool contains(const string_t& key) const;
|
||||
|
||||
bool exists(const string_t& key) const { return contains(key); }
|
||||
|
||||
const basic_value<string_t>& at(const string_t& key) const;
|
||||
|
||||
string_t dumps(std::optional<size_t> indent = std::nullopt) const
|
||||
{
|
||||
return indent ? format(*indent) : to_string();
|
||||
}
|
||||
|
||||
string_t to_string() const;
|
||||
|
||||
string_t format(size_t indent = 4) const { return format(indent, 0); }
|
||||
|
||||
template <typename value_t>
|
||||
bool all() const;
|
||||
template <typename value_t, template <typename...> typename map_t = std::map>
|
||||
map_t<string_t, value_t> as_map() const;
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_from_json_object_in_templ_spec<value_t, string_t>::value,
|
||||
bool> = true>
|
||||
value_t as() const&
|
||||
{
|
||||
value_t res;
|
||||
ext::jsonization<string_t, value_t>().from_json_object(*this, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_move_from_json_object_in_templ_spec<value_t, string_t>::value,
|
||||
bool> = true>
|
||||
value_t as() &&
|
||||
{
|
||||
value_t res;
|
||||
ext::jsonization<string_t, value_t>().move_from_json_object(std::move(*this), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Usage: get(key_1, key_2, ..., default_value);
|
||||
template <typename... key_then_default_value_t>
|
||||
auto get(key_then_default_value_t&&... keys_then_default_value) const;
|
||||
|
||||
template <typename value_t = basic_value<string_t>>
|
||||
std::optional<value_t> find(const string_t& key) const;
|
||||
|
||||
template <typename... args_t>
|
||||
decltype(auto) emplace(args_t&&... args);
|
||||
template <typename... args_t>
|
||||
decltype(auto) insert(args_t&&... args);
|
||||
|
||||
void clear() noexcept;
|
||||
bool erase(const string_t& key);
|
||||
bool erase(iterator iter);
|
||||
|
||||
iterator begin() noexcept;
|
||||
iterator end() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
basic_value<string_t>& operator[](const string_t& key);
|
||||
basic_value<string_t>& operator[](string_t&& key);
|
||||
|
||||
basic_object<string_t> operator|(const basic_object<string_t>& rhs) const&;
|
||||
basic_object<string_t> operator|(basic_object<string_t>&& rhs) const&;
|
||||
basic_object<string_t> operator|(const basic_object<string_t>& rhs) &&;
|
||||
basic_object<string_t> operator|(basic_object<string_t>&& rhs) &&;
|
||||
|
||||
basic_object<string_t>& operator|=(const basic_object<string_t>& rhs);
|
||||
basic_object<string_t>& operator|=(basic_object<string_t>&& rhs);
|
||||
|
||||
basic_object<string_t>& operator=(const basic_object<string_t>&) = default;
|
||||
basic_object<string_t>& operator=(basic_object<string_t>&&) = default;
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
std::enable_if_t<std::is_convertible_v<value_t, basic_object<string_t>>, bool> = true>
|
||||
basic_object<string_t>& operator=(value_t rhs)
|
||||
{
|
||||
return *this = basic_object<string_t>(std::move(rhs));
|
||||
}
|
||||
|
||||
bool operator==(const basic_object<string_t>& rhs) const;
|
||||
|
||||
bool operator!=(const basic_object<string_t>& rhs) const { return !(*this == rhs); }
|
||||
|
||||
template <
|
||||
typename value_t,
|
||||
template <typename...> typename map_t = std::map,
|
||||
std::enable_if_t<_utils::is_map<map_t<string_t, value_t>>, bool> = true>
|
||||
explicit operator map_t<string_t, value_t>() const
|
||||
{
|
||||
return as_map<value_t, map_t>();
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() const&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().from_json(*this, dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() const&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().from_json_object(*this, dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_move_from_json_in_templ_spec<jsonization_t, string_t>::value
|
||||
&& !_utils::has_move_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() &&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().from_json(std::move(*this), dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <
|
||||
typename jsonization_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_move_from_json_object_in_templ_spec<jsonization_t, string_t>::value,
|
||||
bool> = true>
|
||||
explicit operator jsonization_t() &&
|
||||
{
|
||||
jsonization_t dst {};
|
||||
if (!ext::jsonization<string_t, jsonization_t>().move_from_json_object(
|
||||
std::move(*this),
|
||||
dst)) {
|
||||
throw exception("Wrong JSON");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... key_then_default_value_t, size_t... keys_indexes_t>
|
||||
auto
|
||||
get(std::tuple<key_then_default_value_t...> keys_then_default_value,
|
||||
std::index_sequence<keys_indexes_t...>) const;
|
||||
template <typename value_t, typename... rest_keys_t>
|
||||
auto get_helper(const value_t& default_value, const string_t& key, rest_keys_t&&... rest) const;
|
||||
template <typename value_t>
|
||||
auto get_helper(const value_t& default_value, const string_t& key) const;
|
||||
|
||||
string_t format(size_t indent, size_t indent_times) const;
|
||||
|
||||
private:
|
||||
raw_object _object_data;
|
||||
};
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_object<string_t>::basic_object(std::initializer_list<value_type> init_list)
|
||||
: _object_data(
|
||||
std::make_move_iterator(init_list.begin()),
|
||||
std::make_move_iterator(init_list.end()))
|
||||
{
|
||||
}
|
||||
|
||||
// template <typename string_t>
|
||||
// inline basic_object<string_t>::basic_object(const basic_value<string_t>& val) :
|
||||
// basic_object<string_t>(val.as_object())
|
||||
//{}
|
||||
//
|
||||
// template <typename string_t>
|
||||
// inline basic_object<string_t>::basic_object(basic_value<string_t>&& val)
|
||||
// : basic_object<string_t>(std::move(val.as_object()))
|
||||
//{}
|
||||
|
||||
template <typename string_t>
|
||||
inline bool basic_object<string_t>::contains(const string_t& key) const
|
||||
{
|
||||
return _object_data.find(key) != _object_data.cend();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline const basic_value<string_t>& basic_object<string_t>::at(const string_t& key) const
|
||||
{
|
||||
return _object_data.at(key);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline void basic_object<string_t>::clear() noexcept
|
||||
{
|
||||
_object_data.clear();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline bool basic_object<string_t>::erase(const string_t& key)
|
||||
{
|
||||
return _object_data.erase(key) > 0 ? true : false;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline bool basic_object<string_t>::erase(iterator iter)
|
||||
{
|
||||
return _object_data.erase(iter) != _object_data.end();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... args_t>
|
||||
inline decltype(auto) basic_object<string_t>::emplace(args_t&&... args)
|
||||
{
|
||||
static_assert(
|
||||
std::is_constructible_v<value_type, args_t...>,
|
||||
"Parameter can't be used to construct a raw_object::value_type");
|
||||
return _object_data.insert_or_assign(std::forward<args_t>(args)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... args_t>
|
||||
inline decltype(auto) basic_object<string_t>::insert(args_t&&... args)
|
||||
{
|
||||
return emplace(std::forward<args_t>(args)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline string_t basic_object<string_t>::to_string() const
|
||||
{
|
||||
string_t str { '{' };
|
||||
for (auto iter = _object_data.cbegin(); iter != _object_data.cend();) {
|
||||
const auto& [key, val] = *iter;
|
||||
str +=
|
||||
char_t('"') + _utils::unescape_string(key) + string_t { '\"', ':' } + val.to_string();
|
||||
if (++iter != _object_data.cend()) {
|
||||
str += ',';
|
||||
}
|
||||
}
|
||||
str += char_t('}');
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline string_t basic_object<string_t>::format(size_t indent, size_t indent_times) const
|
||||
{
|
||||
const string_t tail_indent(indent * indent_times, ' ');
|
||||
const string_t body_indent(indent * (indent_times + 1), ' ');
|
||||
|
||||
string_t str { '{', '\n' };
|
||||
for (auto iter = _object_data.cbegin(); iter != _object_data.cend();) {
|
||||
const auto& [key, val] = *iter;
|
||||
str += body_indent + char_t('"') + _utils::unescape_string(key)
|
||||
+ string_t { '\"', ':', ' ' } + val.format(indent, indent_times + 1);
|
||||
if (++iter != _object_data.cend()) {
|
||||
str += ',';
|
||||
}
|
||||
str += '\n';
|
||||
}
|
||||
str += tail_indent + char_t('}');
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t>
|
||||
inline bool basic_object<string_t>::all() const
|
||||
{
|
||||
for (const auto& [_, val] : _object_data) {
|
||||
if (!val.template is<value_t>()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t, template <typename...> typename map_t>
|
||||
inline map_t<string_t, value_t> basic_object<string_t>::as_map() const
|
||||
{
|
||||
return as<map_t<string_t, value_t>>();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... key_then_default_value_t>
|
||||
inline auto basic_object<string_t>::get(key_then_default_value_t&&... keys_then_default_value) const
|
||||
{
|
||||
return get(
|
||||
std::forward_as_tuple(keys_then_default_value...),
|
||||
std::make_index_sequence<sizeof...(keys_then_default_value) - 1> {});
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename... key_then_default_value_t, size_t... keys_indexes_t>
|
||||
inline auto basic_object<string_t>::get(
|
||||
std::tuple<key_then_default_value_t...> keys_then_default_value,
|
||||
std::index_sequence<keys_indexes_t...>) const
|
||||
{
|
||||
constexpr unsigned long default_value_index = sizeof...(key_then_default_value_t) - 1;
|
||||
return get_helper(
|
||||
std::get<default_value_index>(keys_then_default_value),
|
||||
std::get<keys_indexes_t>(keys_then_default_value)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t, typename... rest_keys_t>
|
||||
inline auto basic_object<string_t>::get_helper(
|
||||
const value_t& default_value,
|
||||
const string_t& key,
|
||||
rest_keys_t&&... rest) const
|
||||
{
|
||||
constexpr bool is_json = std::is_same_v<basic_value<string_t>, value_t>
|
||||
|| std::is_same_v<basic_array<string_t>, value_t>
|
||||
|| std::is_same_v<basic_object<string_t>, value_t>;
|
||||
constexpr bool is_string = std::is_constructible_v<string_t, value_t> && !is_json;
|
||||
|
||||
if (!contains(key)) {
|
||||
if constexpr (is_string) {
|
||||
return string_t(default_value);
|
||||
}
|
||||
else {
|
||||
return value_t(default_value);
|
||||
}
|
||||
}
|
||||
|
||||
return at(key).get_helper(default_value, std::forward<rest_keys_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t>
|
||||
inline auto
|
||||
basic_object<string_t>::get_helper(const value_t& default_value, const string_t& key) const
|
||||
{
|
||||
constexpr bool is_json = std::is_same_v<basic_value<string_t>, value_t>
|
||||
|| std::is_same_v<basic_array<string_t>, value_t>
|
||||
|| std::is_same_v<basic_object<string_t>, value_t>;
|
||||
constexpr bool is_string = std::is_constructible_v<string_t, value_t> && !is_json;
|
||||
|
||||
if (!contains(key)) {
|
||||
if constexpr (is_string) {
|
||||
return string_t(default_value);
|
||||
}
|
||||
else {
|
||||
return value_t(default_value);
|
||||
}
|
||||
}
|
||||
|
||||
auto val = _object_data.at(key);
|
||||
if (val.template is<value_t>()) {
|
||||
if constexpr (is_string) {
|
||||
return val.template as<string_t>();
|
||||
}
|
||||
else {
|
||||
return val.template as<value_t>();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr (is_string) {
|
||||
return string_t(default_value);
|
||||
}
|
||||
else {
|
||||
return value_t(default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
template <typename value_t>
|
||||
inline std::optional<value_t> basic_object<string_t>::find(const string_t& key) const
|
||||
{
|
||||
auto iter = _object_data.find(key);
|
||||
if (iter == _object_data.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto& val = iter->second;
|
||||
return val.template is<value_t>() ? std::optional<value_t>(val.template as<value_t>())
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_object<string_t>::iterator basic_object<string_t>::begin() noexcept
|
||||
{
|
||||
return _object_data.begin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_object<string_t>::iterator basic_object<string_t>::end() noexcept
|
||||
{
|
||||
return _object_data.end();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_object<string_t>::const_iterator
|
||||
basic_object<string_t>::begin() const noexcept
|
||||
{
|
||||
return _object_data.begin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_object<string_t>::const_iterator basic_object<string_t>::end() const noexcept
|
||||
{
|
||||
return _object_data.end();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_object<string_t>::const_iterator
|
||||
basic_object<string_t>::cbegin() const noexcept
|
||||
{
|
||||
return _object_data.cbegin();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline typename basic_object<string_t>::const_iterator basic_object<string_t>::cend() const noexcept
|
||||
{
|
||||
return _object_data.cend();
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_value<string_t>& basic_object<string_t>::operator[](const string_t& key)
|
||||
{
|
||||
return _object_data[key];
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_value<string_t>& basic_object<string_t>::operator[](string_t&& key)
|
||||
{
|
||||
return _object_data[std::move(key)];
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_object<string_t>
|
||||
basic_object<string_t>::operator|(const basic_object<string_t>& rhs) const&
|
||||
{
|
||||
basic_object<string_t> temp = *this;
|
||||
temp._object_data.insert(rhs.begin(), rhs.end());
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_object<string_t> basic_object<string_t>::operator|(basic_object<string_t>&& rhs) const&
|
||||
{
|
||||
basic_object<string_t> temp = *this;
|
||||
// temp._object_data.merge(std::move(rhs._object_data));
|
||||
temp._object_data.insert(
|
||||
std::make_move_iterator(rhs.begin()),
|
||||
std::make_move_iterator(rhs.end()));
|
||||
return temp;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_object<string_t>
|
||||
basic_object<string_t>::operator|(const basic_object<string_t>& rhs) &&
|
||||
{
|
||||
_object_data.insert(rhs.begin(), rhs.end());
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_object<string_t> basic_object<string_t>::operator|(basic_object<string_t>&& rhs) &&
|
||||
{
|
||||
//_object_data.merge(std::move(rhs._object_data));
|
||||
_object_data.insert(std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_object<string_t>& basic_object<string_t>::operator|=(const basic_object<string_t>& rhs)
|
||||
{
|
||||
_object_data.insert(rhs.begin(), rhs.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline basic_object<string_t>& basic_object<string_t>::operator|=(basic_object<string_t>&& rhs)
|
||||
{
|
||||
_object_data.insert(std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline bool basic_object<string_t>::operator==(const basic_object<string_t>& rhs) const
|
||||
{
|
||||
return _object_data == rhs._object_data;
|
||||
}
|
||||
|
||||
template <
|
||||
typename ostream_t,
|
||||
typename string_t,
|
||||
typename std_ostream_t = std::basic_ostream<
|
||||
typename string_t::value_type,
|
||||
std::char_traits<typename string_t::value_type>>,
|
||||
typename enable_t = std::enable_if_t<
|
||||
std::is_same_v<std_ostream_t, ostream_t> || std::is_base_of_v<std_ostream_t, ostream_t>>>
|
||||
ostream_t& operator<<(ostream_t& out, const basic_object<string_t>& obj)
|
||||
{
|
||||
out << obj.format();
|
||||
return out;
|
||||
}
|
||||
} // namespace json
|
||||
207
3rdparty/include/meojson/common/serialization.hpp
vendored
Normal file
207
3rdparty/include/meojson/common/serialization.hpp
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "types.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace json
|
||||
{
|
||||
namespace _serialization_helper
|
||||
{
|
||||
template <typename in_t, typename serializer_t>
|
||||
class is_serializable
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<serializer_t>()(std::declval<U>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<in_t>(0))::value;
|
||||
};
|
||||
|
||||
struct empty_serializer
|
||||
{
|
||||
// sample:
|
||||
// json::value operator()(const type_1&) const { return ...; }
|
||||
// json::value operator()(const type_2&) const { return ...; }
|
||||
// json::value operator()(const type_3&) const { return ...; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void unable_to_serialize()
|
||||
{
|
||||
static_assert(
|
||||
!sizeof(T),
|
||||
"Unable to serialize T. "
|
||||
#ifdef _MSC_VER
|
||||
"See T below: " __FUNCSIG__
|
||||
#else
|
||||
// "See T below: " __PRETTY_FUNCTION__
|
||||
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
namespace _serialization_helper
|
||||
{
|
||||
template <typename out_t, typename deserializer_t, typename string_t = default_string_t>
|
||||
class is_deserializable
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<deserializer_t>()(std::declval<basic_value<string_t>>(), std::declval<U&>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<out_t>(0))::value;
|
||||
};
|
||||
|
||||
struct empty_deserializer
|
||||
{
|
||||
// sample:
|
||||
// bool operator()(const json::value&, type_1&) const { return ...; }
|
||||
// bool operator()(const json::value&, type_2&) const { return ...; }
|
||||
// bool operator()(const json::value&, type_3&) const { return ...; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void unable_to_deserialize()
|
||||
{
|
||||
static_assert(
|
||||
!sizeof(T),
|
||||
"Unable to deserialize T. "
|
||||
#ifdef _MSC_VER
|
||||
"See T below: " __FUNCSIG__
|
||||
#else
|
||||
// "See T below: " __PRETTY_FUNCTION__
|
||||
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename in_t,
|
||||
typename serializer_t = _serialization_helper::empty_serializer,
|
||||
typename string_t = default_string_t>
|
||||
basic_value<string_t> serialize(in_t&& in, const serializer_t& serializer = {})
|
||||
{
|
||||
if constexpr (_serialization_helper::is_serializable<in_t, serializer_t>::value) {
|
||||
return serializer(std::forward<in_t>(in));
|
||||
}
|
||||
else if constexpr (
|
||||
_utils::is_collection<std::decay_t<in_t>> || _utils::is_fixed_array<std::decay_t<in_t>>) {
|
||||
basic_array<string_t> arr;
|
||||
for (auto&& elem : in) {
|
||||
using elem_t = decltype(elem);
|
||||
|
||||
auto j_elem =
|
||||
serialize<elem_t, serializer_t, string_t>(std::forward<elem_t>(elem), serializer);
|
||||
arr.emplace_back(std::move(j_elem));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
else if constexpr (_utils::is_map<std::decay_t<in_t>>) {
|
||||
basic_object<string_t> obj;
|
||||
for (auto&& [key, elem] : in) {
|
||||
using key_t = decltype(key);
|
||||
using elem_t = decltype(elem);
|
||||
|
||||
auto j_elem =
|
||||
serialize<elem_t, serializer_t, string_t>(std::forward<elem_t>(elem), serializer);
|
||||
obj.emplace(std::forward<key_t>(key), std::move(j_elem));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
else if constexpr (std::is_constructible_v<basic_value<string_t>, in_t>) {
|
||||
return basic_value<string_t>(std::forward<in_t>(in));
|
||||
}
|
||||
else {
|
||||
_serialization_helper::unable_to_serialize<in_t>();
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename out_t,
|
||||
typename deserializer_t = _serialization_helper::empty_deserializer,
|
||||
typename string_t = default_string_t>
|
||||
bool deserialize(
|
||||
const basic_value<string_t>& in,
|
||||
out_t& out,
|
||||
const deserializer_t& deserializer = {})
|
||||
{
|
||||
if constexpr (_serialization_helper::is_deserializable<out_t, deserializer_t>::value) {
|
||||
return deserializer(in, out);
|
||||
}
|
||||
else if constexpr (_utils::is_collection<std::decay_t<out_t>>) {
|
||||
if (!in.is_array()) {
|
||||
return false;
|
||||
}
|
||||
for (auto&& j_elem : in.as_array()) {
|
||||
using elem_t = typename out_t::value_type;
|
||||
elem_t elem {};
|
||||
if (!deserialize<elem_t, deserializer_t, string_t>(j_elem, elem, deserializer)) {
|
||||
return false;
|
||||
}
|
||||
if constexpr (_as_collection_helper::has_emplace_back<out_t>::value) {
|
||||
out.emplace_back(std::move(elem));
|
||||
}
|
||||
else {
|
||||
out.emplace(std::move(elem));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if constexpr (_utils::is_fixed_array<std::decay_t<out_t>>) {
|
||||
if (!in.is_array()) {
|
||||
return false;
|
||||
}
|
||||
auto&& in_as_arr = in.as_array();
|
||||
constexpr size_t out_size = _utils::fixed_array_size<out_t>;
|
||||
if (in_as_arr.size() != out_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < out_size; ++i) {
|
||||
auto&& j_elem = in_as_arr.at(i);
|
||||
using elem_t = typename out_t::value_type;
|
||||
elem_t elem {};
|
||||
if (!deserialize<elem_t, deserializer_t, string_t>(j_elem, elem, deserializer)) {
|
||||
return false;
|
||||
}
|
||||
out.at(i) = std::move(elem);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if constexpr (_utils::is_map<std::decay_t<out_t>>) {
|
||||
if (!in.is_object()) {
|
||||
return false;
|
||||
}
|
||||
for (auto&& [key, j_elem] : in.as_object()) {
|
||||
using elem_t = typename out_t::mapped_type;
|
||||
elem_t elem {};
|
||||
if (!deserialize<elem_t, deserializer_t, string_t>(j_elem, elem, deserializer)) {
|
||||
return false;
|
||||
}
|
||||
out.emplace(std::forward<decltype(key)>(key), std::move(elem));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_constructible_v<out_t, basic_value<string_t>>) {
|
||||
out = out_t(in);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
_serialization_helper::unable_to_deserialize<out_t>();
|
||||
}
|
||||
}
|
||||
} // namespace json
|
||||
7
3rdparty/include/meojson/common/types.hpp
vendored
Normal file
7
3rdparty/include/meojson/common/types.hpp
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "array.hpp"
|
||||
#include "object.hpp"
|
||||
#include "value.hpp"
|
||||
473
3rdparty/include/meojson/common/utils.hpp
vendored
Normal file
473
3rdparty/include/meojson/common/utils.hpp
vendored
Normal file
@@ -0,0 +1,473 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace json
|
||||
{
|
||||
template <typename string_t>
|
||||
class basic_value;
|
||||
template <typename string_t>
|
||||
class basic_array;
|
||||
template <typename string_t>
|
||||
class basic_object;
|
||||
|
||||
using default_string_t = std::string;
|
||||
|
||||
using value = basic_value<default_string_t>;
|
||||
using array = basic_array<default_string_t>;
|
||||
using object = basic_object<default_string_t>;
|
||||
|
||||
using wvalue = basic_value<std::wstring>;
|
||||
using warray = basic_array<std::wstring>;
|
||||
using wobject = basic_object<std::wstring>;
|
||||
}
|
||||
|
||||
namespace json::ext
|
||||
{
|
||||
template <typename string_t, typename T, typename = void>
|
||||
class jsonization
|
||||
{
|
||||
public:
|
||||
// json::value to_json(const T&) const;
|
||||
// bool check_json(const json::value&) const;
|
||||
// bool from_json(const json::value&, T&) const;
|
||||
};
|
||||
}
|
||||
|
||||
namespace json::_utils
|
||||
{
|
||||
template <typename T>
|
||||
using iterator_t = decltype(std::declval<T&>().begin());
|
||||
template <typename T>
|
||||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
template <typename T>
|
||||
using iter_value_t = typename std::iterator_traits<remove_cvref_t<T>>::value_type;
|
||||
template <typename R>
|
||||
using range_value_t = iter_value_t<iterator_t<R>>;
|
||||
|
||||
template <typename T, typename = void>
|
||||
constexpr bool is_string = false;
|
||||
template <typename T>
|
||||
constexpr bool is_string<T, std::void_t<typename T::traits_type>> =
|
||||
std::is_same_v<typename T::traits_type, std::char_traits<typename T::value_type>>;
|
||||
|
||||
template <typename T, typename = void>
|
||||
constexpr bool is_container = false;
|
||||
template <typename T>
|
||||
constexpr bool is_container<T, std::void_t<typename T::value_type, range_value_t<T>>> =
|
||||
std::is_same_v<typename T::value_type, range_value_t<T>> && !is_string<T>;
|
||||
|
||||
template <typename T, typename = void>
|
||||
constexpr bool is_map = false;
|
||||
template <typename T>
|
||||
constexpr bool is_map<T, std::void_t<typename T::key_type, typename T::mapped_type>> =
|
||||
is_container<T>;
|
||||
|
||||
template <typename T, typename = void>
|
||||
constexpr bool is_fixed_array = false;
|
||||
template <template <typename, size_t> typename arr_t, typename value_t, size_t size>
|
||||
constexpr bool is_fixed_array<arr_t<value_t, size>> = true;
|
||||
|
||||
template <typename T, typename = std::enable_if_t<is_fixed_array<T>>>
|
||||
constexpr size_t fixed_array_size = 0;
|
||||
template <template <typename, size_t> typename arr_t, typename value_t, size_t size>
|
||||
constexpr size_t fixed_array_size<arr_t<value_t, size>> = size;
|
||||
|
||||
template <typename T, typename = void>
|
||||
constexpr bool is_collection = false;
|
||||
template <typename T>
|
||||
constexpr bool is_collection<T> = is_container<T> && !is_map<T> && !is_fixed_array<T>;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_variant = false;
|
||||
template <typename... args_t>
|
||||
constexpr bool is_variant<std::variant<args_t...>> = true;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_tuple = false;
|
||||
template <typename... args_t>
|
||||
constexpr bool is_tuple<std::tuple<args_t...>> = true;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_pair = false;
|
||||
template <typename... args_t>
|
||||
constexpr bool is_pair<std::pair<args_t...>> = true;
|
||||
|
||||
template <typename T, typename = void>
|
||||
constexpr bool is_tuple_like = false;
|
||||
template <template <typename...> typename tuple_t, typename... args_t>
|
||||
constexpr bool is_tuple_like<
|
||||
tuple_t<args_t...>,
|
||||
std::void_t<decltype(std::tuple_size<tuple_t<args_t...>>::value)>> =
|
||||
std::tuple_size<tuple_t<args_t...>>::value == sizeof...(args_t);
|
||||
|
||||
template <typename T>
|
||||
class has_emplace_back
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int) -> decltype(std::declval<U>().emplace_back(), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class has_to_json_in_member
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int) -> decltype(std::declval<U>().to_json(), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_check_json_in_member
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<U>().check_json(std::declval<json::basic_value<string_t>>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_from_json_in_member
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<U>().from_json(std::declval<json::basic_value<string_t>>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_to_json_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().to_json(std::declval<U>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_check_json_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().check_json(std::declval<json::basic_value<string_t>>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_from_json_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().from_json(std::declval<json::basic_value<string_t>>(), std::declval<U&>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_move_to_json_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_to_json(std::declval<U>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_move_from_json_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_from_json(std::declval<json::basic_value<string_t>>(), std::declval<U&>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_to_json_array_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().to_json_array(std::declval<U>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_check_json_array_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().check_json_array(std::declval<json::basic_array<string_t>>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_from_json_array_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().from_json_array(std::declval<json::basic_array<string_t>>(), std::declval<U&>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_move_to_json_array_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_to_json_array(std::declval<U>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_move_from_json_array_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_from_json_array(std::declval<json::basic_array<string_t>>(), std::declval<U&>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_to_json_object_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().to_json_object(std::declval<U>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_check_json_object_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().check_json_object(std::declval<json::basic_object<string_t>>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_from_json_object_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().from_json_object(std::declval<json::basic_object<string_t>>(), std::declval<U&>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_move_to_json_object_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_to_json_object(std::declval<U>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename string_t>
|
||||
class has_move_from_json_object_in_templ_spec
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int)
|
||||
-> decltype(std::declval<ext::jsonization<string_t, U>>().move_from_json_object(std::declval<json::basic_object<string_t>>(), std::declval<U&>()), std::true_type());
|
||||
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename string_t>
|
||||
inline constexpr string_t unescape_string(const string_t& str)
|
||||
{
|
||||
using char_t = typename string_t::value_type;
|
||||
|
||||
string_t result {};
|
||||
auto cur = str.cbegin();
|
||||
auto end = str.cend();
|
||||
auto no_escape_beg = cur;
|
||||
char_t escape = 0;
|
||||
|
||||
for (; cur != end; ++cur) {
|
||||
switch (*cur) {
|
||||
case '"':
|
||||
escape = '"';
|
||||
break;
|
||||
case '\\':
|
||||
escape = '\\';
|
||||
break;
|
||||
case '\b':
|
||||
escape = 'b';
|
||||
break;
|
||||
case '\f':
|
||||
escape = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
escape = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
escape = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
escape = 't';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (escape) {
|
||||
result += string_t(no_escape_beg, cur) + char_t('\\') + escape;
|
||||
no_escape_beg = cur + 1;
|
||||
escape = 0;
|
||||
}
|
||||
}
|
||||
result += string_t(no_escape_beg, cur);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline constexpr string_t true_string()
|
||||
{
|
||||
return { 't', 'r', 'u', 'e' };
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline constexpr string_t false_string()
|
||||
{
|
||||
return { 'f', 'a', 'l', 's', 'e' };
|
||||
}
|
||||
|
||||
template <typename string_t>
|
||||
inline constexpr string_t null_string()
|
||||
{
|
||||
return { 'n', 'u', 'l', 'l' };
|
||||
}
|
||||
|
||||
template <typename string_t, typename any_t>
|
||||
inline string_t to_basic_string(any_t&& arg)
|
||||
{
|
||||
#ifdef MEOJSON_KEEP_FLOATING_PRECISION
|
||||
using real_type = std::remove_reference_t<any_t>;
|
||||
if constexpr (std::is_floating_point_v<real_type>) {
|
||||
if constexpr (std::is_same_v<string_t, std::string>) {
|
||||
std::ostringstream oss;
|
||||
oss << std::setprecision(std::numeric_limits<real_type>::max_digits10) << arg;
|
||||
return oss.str();
|
||||
}
|
||||
else if constexpr (std::is_same_v<string_t, std::wstring>) {
|
||||
std::wostringstream oss;
|
||||
oss << std::setprecision(std::numeric_limits<real_type>::max_digits10) << arg;
|
||||
return oss.str();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if constexpr (std::is_same_v<string_t, std::string>) {
|
||||
return std::to_string(std::forward<any_t>(arg));
|
||||
}
|
||||
else if constexpr (std::is_same_v<string_t, std::wstring>) {
|
||||
return std::to_wstring(std::forward<any_t>(arg));
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(any_t), "Unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace json::_utils
|
||||
|
||||
#include "../reflection/extensions.hpp"
|
||||
1142
3rdparty/include/meojson/common/value.hpp
vendored
Normal file
1142
3rdparty/include/meojson/common/value.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
3rdparty/include/meojson/json.hpp
vendored
Normal file
9
3rdparty/include/meojson/json.hpp
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "parser/parser.hpp"
|
||||
#include "reflection/jsonization.hpp"
|
||||
|
||||
// IWYU pragma: end_exports
|
||||
139
3rdparty/include/meojson/parser/bitops.hpp
vendored
Normal file
139
3rdparty/include/meojson/parser/bitops.hpp
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
||||
#include <bit>
|
||||
|
||||
namespace json::_bitops
|
||||
{
|
||||
using std::countl_one;
|
||||
using std::countl_zero;
|
||||
using std::countr_one;
|
||||
using std::countr_zero;
|
||||
|
||||
inline constexpr bool is_little_endian()
|
||||
{
|
||||
return std::endian::native == std::endian::little;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#include <cstdint>
|
||||
|
||||
namespace json::_bitops
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
inline constexpr int countl_zero(uint32_t x)
|
||||
{
|
||||
if constexpr (sizeof(uint32_t) == sizeof(unsigned int)) {
|
||||
return x == 0 ? 32 : __builtin_clz(x);
|
||||
}
|
||||
if constexpr (sizeof(uint32_t) == sizeof(unsigned long)) {
|
||||
return x == 0 ? 32 : __builtin_clzl(x);
|
||||
}
|
||||
return x == 0 ? 32 : __builtin_clzll(x);
|
||||
}
|
||||
|
||||
inline constexpr int countr_zero(uint32_t x)
|
||||
{
|
||||
if constexpr (sizeof(uint32_t) == sizeof(unsigned int)) {
|
||||
return x == 0 ? 32 : __builtin_ctz(x);
|
||||
}
|
||||
if constexpr (sizeof(uint32_t) == sizeof(unsigned long)) {
|
||||
return x == 0 ? 32 : __builtin_ctzl(x);
|
||||
}
|
||||
return x == 0 ? 32 : __builtin_ctzll(x);
|
||||
}
|
||||
|
||||
inline constexpr int countl_zero(uint64_t x)
|
||||
{
|
||||
return x == 0 ? 64 : __builtin_clzll(x);
|
||||
}
|
||||
|
||||
inline constexpr int countr_zero(uint64_t x)
|
||||
{
|
||||
return x == 0 ? 64 : __builtin_ctzll(x);
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
#ifdef __AVX2__
|
||||
// lzcnt intrinsics is not constexpr
|
||||
inline int countl_zero(uint32_t x)
|
||||
{
|
||||
return __lzcnt(x);
|
||||
}
|
||||
|
||||
inline int countr_zero(uint32_t x)
|
||||
{
|
||||
return _tzcnt_u32(x);
|
||||
}
|
||||
|
||||
inline int countl_zero(uint64_t x)
|
||||
{
|
||||
return (int)__lzcnt64(x);
|
||||
}
|
||||
|
||||
inline int countr_zero(uint64_t x)
|
||||
{
|
||||
return (int)_tzcnt_u64(x);
|
||||
}
|
||||
#else
|
||||
inline constexpr int countl_zero(uint32_t x)
|
||||
{
|
||||
unsigned long index = 0;
|
||||
return _BitScanReverse(&index, x) ? 31 - index : 32;
|
||||
}
|
||||
|
||||
inline constexpr int countr_zero(uint32_t x)
|
||||
{
|
||||
unsigned long index = 0;
|
||||
return _BitScanForward(&index, x) ? index : 32;
|
||||
}
|
||||
|
||||
inline constexpr int countl_zero(uint64_t x)
|
||||
{
|
||||
unsigned long index = 0;
|
||||
return _BitScanReverse64(&index, x) ? 63 - index : 64;
|
||||
}
|
||||
|
||||
inline constexpr int countr_zero(uint64_t x)
|
||||
{
|
||||
unsigned long index = 0;
|
||||
return _BitScanForward64(&index, x) ? index : 64;
|
||||
}
|
||||
#endif // __AVX2__
|
||||
#else // compiler
|
||||
#error "bring your own bit counting implementation"
|
||||
#endif
|
||||
inline int countl_one(uint32_t x)
|
||||
{
|
||||
return countl_zero(~x);
|
||||
}
|
||||
|
||||
inline int countr_one(uint32_t x)
|
||||
{
|
||||
return countr_zero(~x);
|
||||
}
|
||||
|
||||
inline int countl_one(uint64_t x)
|
||||
{
|
||||
return countl_zero(~x);
|
||||
}
|
||||
|
||||
inline int countr_one(uint64_t x)
|
||||
{
|
||||
return countr_zero(~x);
|
||||
}
|
||||
|
||||
// no constexpr endian awareness before C++20
|
||||
inline bool is_little_endian()
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t u32;
|
||||
uint8_t u8;
|
||||
} u = { 0x01020304 };
|
||||
|
||||
return u.u8 == 4;
|
||||
}
|
||||
} // namespace json::_bitops
|
||||
#endif // C++20
|
||||
161
3rdparty/include/meojson/parser/packed_bytes.hpp
vendored
Normal file
161
3rdparty/include/meojson/parser/packed_bytes.hpp
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
#include "bitops.hpp"
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define __packed_bytes_strong_inline __attribute__((always_inline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define __packed_bytes_strong_inline __forceinline
|
||||
#else
|
||||
#define __packed_bytes_strong_inline inline
|
||||
#endif
|
||||
|
||||
namespace json::_packed_bytes
|
||||
{
|
||||
struct packed_bytes_trait_none
|
||||
{
|
||||
static constexpr bool available = false;
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
struct packed_bytes
|
||||
{
|
||||
using traits = packed_bytes_trait_none;
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef MEOJSON_DISABLE_PACKED_BYTES
|
||||
#if defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP)
|
||||
#include "packed_bytes_x86.hpp"
|
||||
#elif defined(__ARM_NEON) || defined(_M_ARM) || defined(_M_ARM64)
|
||||
#include "packed_bytes_arm.hpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace json::_packed_bytes
|
||||
{
|
||||
struct packed_bytes_trait_uint64
|
||||
{
|
||||
static constexpr bool available = sizeof(void*) >= 8;
|
||||
static constexpr auto step = 8;
|
||||
using value_type = uint64_t;
|
||||
|
||||
__packed_bytes_strong_inline static value_type load_unaligned(const void* ptr)
|
||||
{
|
||||
value_type result;
|
||||
memcpy((void*)&result, ptr, 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type less(value_type x, uint8_t n)
|
||||
{
|
||||
return (((x)-UINT64_C(0x0101010101010101) * (n)) & ~(x)&UINT64_C(0x8080808080808080));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type is_zero_memberwise(value_type v)
|
||||
{
|
||||
return (((v)-UINT64_C(0x0101010101010101)) & ~(v)&UINT64_C(0x8080808080808080));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static bool is_all_zero(value_type v) { return v == UINT64_C(0); }
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, uint8_t n)
|
||||
{
|
||||
return is_zero_memberwise((x) ^ (UINT64_C(0x0101010101010101) * (n)));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type bitwise_or(value_type a, value_type b)
|
||||
{
|
||||
return a | b;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static size_t first_nonzero_byte(value_type x)
|
||||
{
|
||||
if (_bitops::is_little_endian()) {
|
||||
return _bitops::countr_zero(x) / 8;
|
||||
}
|
||||
else {
|
||||
return _bitops::countl_zero(x) / 8;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct packed_bytes_trait_uint32
|
||||
{
|
||||
static constexpr bool available = true;
|
||||
static constexpr auto step = 4;
|
||||
using value_type = uint32_t;
|
||||
|
||||
__packed_bytes_strong_inline static value_type load_unaligned(const void* ptr)
|
||||
{
|
||||
value_type result;
|
||||
memcpy((void*)&result, ptr, 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type less(value_type x, uint8_t n)
|
||||
{
|
||||
return (((x) - ~UINT32_C(0) / 255 * (n)) & ~(x) & ~UINT32_C(0) / 255 * 128);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type is_zero_memberwise(value_type v)
|
||||
{
|
||||
return (((v)-UINT32_C(0x01010101)) & ~(v)&UINT32_C(0x80808080));
|
||||
;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static bool is_all_zero(value_type v) { return v == UINT32_C(0); }
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, uint8_t n)
|
||||
{
|
||||
return is_zero_memberwise((x) ^ (~UINT32_C(0) / 255 * (n)));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type bitwise_or(value_type a, value_type b)
|
||||
{
|
||||
return a | b;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static size_t first_nonzero_byte(value_type x)
|
||||
{
|
||||
if (_bitops::is_little_endian()) {
|
||||
return _bitops::countr_zero(x) / 8;
|
||||
}
|
||||
else {
|
||||
return _bitops::countl_zero(x) / 8;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct packed_bytes<8>
|
||||
{
|
||||
using traits = packed_bytes_trait_uint64;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct packed_bytes<4>
|
||||
{
|
||||
using traits = packed_bytes_trait_uint32;
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
using packed_bytes_trait = typename packed_bytes<N>::traits;
|
||||
|
||||
using packed_bytes_trait_max = std::conditional_t<
|
||||
packed_bytes_trait<32>::available,
|
||||
packed_bytes_trait<32>,
|
||||
std::conditional_t<
|
||||
packed_bytes_trait<16>::available,
|
||||
packed_bytes_trait<16>,
|
||||
std::conditional_t<
|
||||
packed_bytes_trait<8>::available,
|
||||
packed_bytes_trait<8>,
|
||||
packed_bytes_trait<4>>>>;
|
||||
} // namespace json::_packed_bytes
|
||||
79
3rdparty/include/meojson/parser/packed_bytes_arm.hpp
vendored
Normal file
79
3rdparty/include/meojson/parser/packed_bytes_arm.hpp
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
// current NEON implementation doesn't outperform 64-bit scalar implementation
|
||||
#ifdef MEOJSON_ENABLE_NEON
|
||||
#include "packed_bytes.hpp"
|
||||
#include <arm_neon.h>
|
||||
|
||||
#if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
|
||||
#define __packed_bytes_trait_arm64
|
||||
#endif
|
||||
|
||||
namespace json::_packed_bytes
|
||||
{
|
||||
struct packed_bytes_trait_neon
|
||||
{
|
||||
static constexpr bool available = true;
|
||||
static constexpr auto step = 16;
|
||||
using value_type = uint8x16_t;
|
||||
|
||||
__packed_bytes_strong_inline static value_type load_unaligned(const void* ptr)
|
||||
{
|
||||
return vld1q_u8((uint8_t*)ptr);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type less(value_type x, uint8_t n)
|
||||
{
|
||||
auto bcast = vdupq_n_u8(n);
|
||||
auto is_less = vcltq_u8(x, bcast);
|
||||
return is_less;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, uint8_t n)
|
||||
{
|
||||
return vceqq_u8(x, vdupq_n_u8(n));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, value_type y)
|
||||
{
|
||||
return vceqq_u8(x, y);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type bitwise_or(value_type a, value_type b)
|
||||
{
|
||||
return vorrq_u8(a, b);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static bool is_all_zero(value_type x)
|
||||
{
|
||||
#ifdef __packed_bytes_trait_arm64
|
||||
return vmaxvq_u8(x) == 0;
|
||||
#else
|
||||
auto fold64 = vorr_u64(
|
||||
vget_high_u64(vreinterpretq_u8_u64(x), 0),
|
||||
vget_low_u64(vreinterpretq_u8_u64(x), 1));
|
||||
auto fold32 = vget_lane_u32(vreinterpret_u64_u32(fold64), 0)
|
||||
| vget_lane_u32(vreinterpret_u64_u32(fold64), 1);
|
||||
return fold32 == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static size_t first_nonzero_byte(value_type x)
|
||||
{
|
||||
// https://community.arm.com/arm-community-blogs/b/infrastructure-solutions-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon
|
||||
auto cmp = equal(x, 0);
|
||||
auto res = vshrn_n_u16(cmp, 4);
|
||||
auto mask64 = vget_lane_u64(vreinterpret_u64_u8(res), 0);
|
||||
return _bitops::countr_one(mask64) >> 2;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct packed_bytes<16>
|
||||
{
|
||||
using traits = packed_bytes_trait_neon;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
140
3rdparty/include/meojson/parser/packed_bytes_x86.hpp
vendored
Normal file
140
3rdparty/include/meojson/parser/packed_bytes_x86.hpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "packed_bytes.hpp"
|
||||
|
||||
#include <emmintrin.h>
|
||||
#if defined(__SSE4_1__) || defined(__AVX2__) || defined(_MSC_VER)
|
||||
// MSVC enables all SSE4.1 intrinsics by default
|
||||
#include <smmintrin.h>
|
||||
#endif
|
||||
|
||||
namespace json::_packed_bytes
|
||||
{
|
||||
struct packed_bytes_trait_sse
|
||||
{
|
||||
static constexpr bool available = true;
|
||||
static constexpr auto step = 16;
|
||||
using value_type = __m128i;
|
||||
|
||||
__packed_bytes_strong_inline static value_type load_unaligned(const void* ptr)
|
||||
{
|
||||
return _mm_loadu_si128(reinterpret_cast<const __m128i*>(ptr));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type less(value_type x, uint8_t n)
|
||||
{
|
||||
auto bcast = _mm_set1_epi8(static_cast<char>(n));
|
||||
auto all1 = _mm_set1_epi8(-1);
|
||||
auto max_with_n = _mm_max_epu8(x, bcast);
|
||||
auto is_greater_or_equal = _mm_cmpeq_epi8(max_with_n, x);
|
||||
auto is_less = _mm_andnot_si128(is_greater_or_equal, all1);
|
||||
return is_less;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, uint8_t n)
|
||||
{
|
||||
return _mm_cmpeq_epi8(x, _mm_set1_epi8(static_cast<char>(n)));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, value_type y)
|
||||
{
|
||||
return _mm_cmpeq_epi8(x, y);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type bitwise_or(value_type a, value_type b)
|
||||
{
|
||||
return _mm_or_si128(a, b);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static bool is_all_zero(value_type x)
|
||||
{
|
||||
#if defined(__SSE4_1__) || defined(__AVX2__) || defined(_MSC_VER)
|
||||
// SSE4.1 path
|
||||
return !!_mm_testz_si128(x, x);
|
||||
#else
|
||||
// SSE2 path
|
||||
auto cmp = _mm_cmpeq_epi8(x, _mm_set1_epi8(0));
|
||||
auto mask = (uint16_t)_mm_movemask_epi8(cmp);
|
||||
return mask == UINT16_C(0xFFFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static size_t first_nonzero_byte(value_type x)
|
||||
{
|
||||
auto cmp = _mm_cmpeq_epi8(x, _mm_set1_epi8(0));
|
||||
auto mask = (uint16_t)_mm_movemask_epi8(cmp);
|
||||
return _bitops::countr_one((uint32_t)mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct packed_bytes<16>
|
||||
{
|
||||
using traits = packed_bytes_trait_sse;
|
||||
};
|
||||
}
|
||||
#ifdef __AVX2__
|
||||
#include <immintrin.h>
|
||||
|
||||
namespace json::_packed_bytes
|
||||
{
|
||||
struct packed_bytes_trait_avx2
|
||||
{
|
||||
static constexpr bool available = true;
|
||||
static constexpr auto step = 32;
|
||||
using value_type = __m256i;
|
||||
|
||||
__packed_bytes_strong_inline static value_type load_unaligned(const void* ptr)
|
||||
{
|
||||
return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(ptr));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type less(value_type x, uint8_t n)
|
||||
{
|
||||
auto bcast = _mm256_set1_epi8(static_cast<char>(n));
|
||||
auto all1 = _mm256_set1_epi8(-1);
|
||||
auto max_with_n = _mm256_max_epu8(x, bcast);
|
||||
auto is_greater_or_equal = _mm256_cmpeq_epi8(max_with_n, x);
|
||||
auto is_less = _mm256_andnot_si256(is_greater_or_equal, all1);
|
||||
return is_less;
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, uint8_t n)
|
||||
{
|
||||
return _mm256_cmpeq_epi8(x, _mm256_set1_epi8(static_cast<char>(n)));
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type equal(value_type x, value_type y)
|
||||
{
|
||||
return _mm256_cmpeq_epi8(x, y);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static value_type bitwise_or(value_type a, value_type b)
|
||||
{
|
||||
return _mm256_or_si256(a, b);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static bool is_all_zero(value_type x)
|
||||
{
|
||||
return (bool)_mm256_testz_si256(x, x);
|
||||
}
|
||||
|
||||
__packed_bytes_strong_inline static size_t first_nonzero_byte(value_type x)
|
||||
{
|
||||
auto cmp = _mm256_cmpeq_epi8(x, _mm256_set1_epi8(0));
|
||||
auto mask = (uint32_t)_mm256_movemask_epi8(cmp);
|
||||
// AVX512 alternative: _mm_cmpeq_epi8_mask
|
||||
return _bitops::countr_one(mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct packed_bytes<32>
|
||||
{
|
||||
using traits = packed_bytes_trait_avx2;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
862
3rdparty/include/meojson/parser/parser.hpp
vendored
Normal file
862
3rdparty/include/meojson/parser/parser.hpp
vendored
Normal file
@@ -0,0 +1,862 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "../common/types.hpp"
|
||||
#include "packed_bytes.hpp"
|
||||
|
||||
namespace json
|
||||
{
|
||||
// ****************************
|
||||
// * parser declare *
|
||||
// ****************************
|
||||
|
||||
template <
|
||||
bool accept_jsonc = false,
|
||||
typename string_t = default_string_t,
|
||||
typename parsing_t = void,
|
||||
typename accel_traits = _packed_bytes::packed_bytes_trait_max>
|
||||
class parser
|
||||
{
|
||||
public:
|
||||
using parsing_iter_t = typename parsing_t::const_iterator;
|
||||
|
||||
public:
|
||||
~parser() noexcept = default;
|
||||
|
||||
static std::optional<basic_value<string_t>> parse(const parsing_t& content);
|
||||
|
||||
private:
|
||||
parser(parsing_iter_t cbegin, parsing_iter_t cend) noexcept
|
||||
: _cur(cbegin)
|
||||
, _end(cend)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
std::optional<basic_value<string_t>> parse();
|
||||
basic_value<string_t> parse_value();
|
||||
|
||||
basic_value<string_t> parse_null();
|
||||
basic_value<string_t> parse_boolean();
|
||||
basic_value<string_t> parse_number();
|
||||
// parse and return a basic_value<string_t> whose type is value_type::string
|
||||
basic_value<string_t> parse_string();
|
||||
basic_value<string_t> parse_array();
|
||||
basic_value<string_t> parse_object();
|
||||
|
||||
// parse and return a string_t
|
||||
std::optional<string_t> parse_stdstring();
|
||||
|
||||
bool skip_string_literal_with_accel();
|
||||
bool skip_whitespace() noexcept;
|
||||
bool skip_comment() noexcept;
|
||||
bool skip_digit();
|
||||
bool skip_unicode_escape(uint16_t& pair_high, string_t& result);
|
||||
|
||||
private:
|
||||
parsing_iter_t _cur;
|
||||
parsing_iter_t _end;
|
||||
};
|
||||
|
||||
// ***************************
|
||||
// * utils declare *
|
||||
// ***************************
|
||||
|
||||
template <typename parsing_t>
|
||||
auto parse(const parsing_t& content);
|
||||
|
||||
template <typename char_t>
|
||||
auto parse(char_t* content);
|
||||
|
||||
template <typename parsing_t>
|
||||
auto parsec(const parsing_t& content);
|
||||
|
||||
template <typename char_t>
|
||||
auto parsec(char_t* content);
|
||||
|
||||
template <
|
||||
typename istream_t,
|
||||
typename = std::enable_if_t<
|
||||
std::is_base_of_v<std::basic_istream<typename istream_t::char_type>, istream_t>>>
|
||||
auto parse(istream_t& istream, bool check_bom = false, bool with_commets = false);
|
||||
|
||||
template <typename ifstream_t = std::ifstream, typename path_t = void>
|
||||
auto open(const path_t& path, bool check_bom = false, bool with_commets = false);
|
||||
|
||||
namespace literals
|
||||
{
|
||||
value operator""_json(const char* str, size_t len);
|
||||
wvalue operator""_json(const wchar_t* str, size_t len);
|
||||
|
||||
value operator""_jvalue(const char* str, size_t len);
|
||||
wvalue operator""_jvalue(const wchar_t* str, size_t len);
|
||||
|
||||
array operator""_jarray(const char* str, size_t len);
|
||||
warray operator""_jarray(const wchar_t* str, size_t len);
|
||||
|
||||
object operator""_jobject(const char* str, size_t len);
|
||||
wobject operator""_jobject(const wchar_t* str, size_t len);
|
||||
}
|
||||
|
||||
template <typename string_t = default_string_t>
|
||||
const basic_value<string_t> invalid_value();
|
||||
|
||||
// *************************
|
||||
// * parser impl *
|
||||
// *************************
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline std::optional<basic_value<string_t>>
|
||||
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse(const parsing_t& content)
|
||||
{
|
||||
return parser<accept_jsonc, string_t, parsing_t, accel_traits>(content.cbegin(), content.cend())
|
||||
.parse();
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline std::optional<basic_value<string_t>>
|
||||
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse()
|
||||
{
|
||||
if (!skip_whitespace()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
basic_value<string_t> result_value;
|
||||
switch (*_cur) {
|
||||
case '[':
|
||||
result_value = parse_array();
|
||||
break;
|
||||
case '{':
|
||||
result_value = parse_object();
|
||||
break;
|
||||
default: // A JSON payload should be an basic_object or basic_array
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!result_value.valid()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// After the parsing is complete, there should be no more content other than spaces behind
|
||||
if (skip_whitespace()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return result_value;
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_value()
|
||||
{
|
||||
switch (*_cur) {
|
||||
case 'n':
|
||||
return parse_null();
|
||||
case 't':
|
||||
case 'f':
|
||||
return parse_boolean();
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return parse_number();
|
||||
case '"':
|
||||
return parse_string();
|
||||
case '[':
|
||||
return parse_array();
|
||||
case '{':
|
||||
return parse_object();
|
||||
default:
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_null()
|
||||
{
|
||||
for (const auto& ch : _utils::null_string<string_t>()) {
|
||||
if (_cur != _end && *_cur == ch) {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
}
|
||||
|
||||
return basic_value<string_t>();
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline basic_value<string_t>
|
||||
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_boolean()
|
||||
{
|
||||
switch (*_cur) {
|
||||
case 't':
|
||||
for (const auto& ch : _utils::true_string<string_t>()) {
|
||||
if (_cur != _end && *_cur == ch) {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case 'f':
|
||||
for (const auto& ch : _utils::false_string<string_t>()) {
|
||||
if (_cur != _end && *_cur == ch) {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_number()
|
||||
{
|
||||
const auto first = _cur;
|
||||
if (*_cur == '-') {
|
||||
++_cur;
|
||||
}
|
||||
|
||||
// numbers cannot have leading zeroes
|
||||
if (_cur != _end && *_cur == '0' && _cur + 1 != _end && std::isdigit(*(_cur + 1))) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if (!skip_digit()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if (*_cur == '.') {
|
||||
++_cur;
|
||||
if (!skip_digit()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
}
|
||||
|
||||
if (*_cur == 'e' || *_cur == 'E') {
|
||||
if (++_cur == _end) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
if (*_cur == '+' || *_cur == '-') {
|
||||
++_cur;
|
||||
}
|
||||
if (!skip_digit()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
}
|
||||
|
||||
return basic_value<string_t>(basic_value<string_t>::value_type::number, string_t(first, _cur));
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_string()
|
||||
{
|
||||
auto string_opt = parse_stdstring();
|
||||
if (!string_opt) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
return basic_value<string_t>(
|
||||
basic_value<string_t>::value_type::string,
|
||||
std::move(string_opt).value());
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_array()
|
||||
{
|
||||
if (*_cur == '[') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if (!skip_whitespace()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
else if (*_cur == ']') {
|
||||
++_cur;
|
||||
// empty basic_array
|
||||
return basic_array<string_t>();
|
||||
}
|
||||
|
||||
typename basic_array<string_t>::raw_array result;
|
||||
while (true) {
|
||||
if (!skip_whitespace()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if constexpr (accept_jsonc) {
|
||||
if (*_cur == ']') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
basic_value<string_t> val = parse_value();
|
||||
|
||||
if (!val.valid() || !skip_whitespace()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
result.emplace_back(std::move(val));
|
||||
|
||||
if (*_cur == ',') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_whitespace() && *_cur == ']') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
return basic_array<string_t>(std::move(result));
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline basic_value<string_t> parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_object()
|
||||
{
|
||||
if (*_cur == '{') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if (!skip_whitespace()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
else if (*_cur == '}') {
|
||||
++_cur;
|
||||
// empty basic_object
|
||||
return basic_object<string_t>();
|
||||
}
|
||||
|
||||
typename basic_object<string_t>::raw_object result;
|
||||
while (true) {
|
||||
if (!skip_whitespace()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if constexpr (accept_jsonc) {
|
||||
if (*_cur == '}') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto key_opt = parse_stdstring();
|
||||
|
||||
if (key_opt && skip_whitespace() && *_cur == ':') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if (!skip_whitespace()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
basic_value<string_t> val = parse_value();
|
||||
|
||||
if (!val.valid() || !skip_whitespace()) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
auto emplaced = result.emplace(std::move(*key_opt), std::move(val)).second;
|
||||
if (!emplaced) {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
if (*_cur == ',') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_whitespace() && *_cur == '}') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return invalid_value<string_t>();
|
||||
}
|
||||
|
||||
return basic_object<string_t>(std::move(result));
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline std::optional<string_t>
|
||||
parser<accept_jsonc, string_t, parsing_t, accel_traits>::parse_stdstring()
|
||||
{
|
||||
if (*_cur == '"') {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
string_t result;
|
||||
auto no_escape_beg = _cur;
|
||||
uint16_t pair_high = 0;
|
||||
|
||||
while (_cur != _end) {
|
||||
if constexpr (sizeof(*_cur) == 1 && accel_traits::available) {
|
||||
if (!skip_string_literal_with_accel()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
switch (*_cur) {
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
return std::nullopt;
|
||||
case '\\': {
|
||||
result += string_t(no_escape_beg, _cur++);
|
||||
if (_cur == _end) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (pair_high && *_cur != 'u') {
|
||||
return std::nullopt;
|
||||
}
|
||||
switch (*_cur) {
|
||||
case '"':
|
||||
result.push_back('"');
|
||||
break;
|
||||
case '\\':
|
||||
result.push_back('\\');
|
||||
break;
|
||||
case '/':
|
||||
result.push_back('/');
|
||||
break;
|
||||
case 'b':
|
||||
result.push_back('\b');
|
||||
break;
|
||||
case 'f':
|
||||
result.push_back('\f');
|
||||
break;
|
||||
case 'n':
|
||||
result.push_back('\n');
|
||||
break;
|
||||
case 'r':
|
||||
result.push_back('\r');
|
||||
break;
|
||||
case 't':
|
||||
result.push_back('\t');
|
||||
break;
|
||||
case 'u':
|
||||
if (!skip_unicode_escape(pair_high, result)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Illegal backslash escape
|
||||
return std::nullopt;
|
||||
}
|
||||
no_escape_beg = ++_cur;
|
||||
break;
|
||||
}
|
||||
case '"': {
|
||||
if (pair_high) {
|
||||
return std::nullopt;
|
||||
}
|
||||
result += string_t(no_escape_beg, _cur++);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
if (pair_high) {
|
||||
return std::nullopt;
|
||||
}
|
||||
++_cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_unicode_escape(
|
||||
uint16_t& pair_high,
|
||||
string_t& result)
|
||||
{
|
||||
uint16_t cp = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (++_cur == _end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::isxdigit(static_cast<unsigned char>(*_cur))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cp <<= 4;
|
||||
|
||||
if ('0' <= *_cur && *_cur <= '9') {
|
||||
cp |= *_cur - '0';
|
||||
}
|
||||
else if ('a' <= *_cur && *_cur <= 'f') {
|
||||
cp |= *_cur - 'a' + 10;
|
||||
}
|
||||
else if ('A' <= *_cur && *_cur <= 'F') {
|
||||
cp |= *_cur - 'A' + 10;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ext_cp = cp;
|
||||
uint16_t hi_cp = 0, lo_cp = 0;
|
||||
|
||||
if (0xD800 <= cp && cp <= 0xDBFF) {
|
||||
if (pair_high) {
|
||||
return false;
|
||||
}
|
||||
pair_high = cp;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (0xDC00 <= cp && cp <= 0xDFFF) {
|
||||
if (!pair_high) {
|
||||
return false;
|
||||
}
|
||||
ext_cp = (((pair_high - 0xD800) << 10) | (cp - 0xDC00)) + 0x10000;
|
||||
hi_cp = pair_high;
|
||||
lo_cp = cp;
|
||||
pair_high = 0;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<typename string_t::value_type, char>) {
|
||||
// utf8
|
||||
if (ext_cp <= 0x7F) {
|
||||
result.push_back(static_cast<char>(ext_cp));
|
||||
}
|
||||
else if (ext_cp <= 0x7FF) {
|
||||
result.push_back(static_cast<char>(((ext_cp >> 6) & 0b00011111) | 0b11000000u));
|
||||
result.push_back(static_cast<char>((ext_cp & 0b00111111) | 0b10000000u));
|
||||
}
|
||||
else if (ext_cp <= 0xFFFF) {
|
||||
result.push_back(static_cast<char>(((ext_cp >> 12) & 0b00001111) | 0b11100000u));
|
||||
result.push_back(static_cast<char>(((ext_cp >> 6) & 0b00111111) | 0b10000000u));
|
||||
result.push_back(static_cast<char>((ext_cp & 0b00111111) | 0b10000000u));
|
||||
}
|
||||
else {
|
||||
result.push_back(static_cast<char>(((ext_cp >> 18) & 0b00000111) | 0b11110000u));
|
||||
result.push_back(static_cast<char>(((ext_cp >> 12) & 0b00111111) | 0b10000000u));
|
||||
result.push_back(static_cast<char>(((ext_cp >> 6) & 0b00111111) | 0b10000000u));
|
||||
result.push_back(static_cast<char>((ext_cp & 0b00111111) | 0b10000000u));
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<typename string_t::value_type, wchar_t>) {
|
||||
if constexpr (sizeof(wchar_t) == 4) {
|
||||
result.push_back(static_cast<wchar_t>(ext_cp));
|
||||
}
|
||||
else if constexpr (sizeof(wchar_t) == 2) {
|
||||
if (ext_cp <= 0xFFFF) {
|
||||
result.push_back(static_cast<wchar_t>(ext_cp));
|
||||
}
|
||||
else {
|
||||
result.push_back(static_cast<wchar_t>(hi_cp));
|
||||
result.push_back(static_cast<wchar_t>(lo_cp));
|
||||
}
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(typename string_t::value_type), "Unsupported wchar");
|
||||
}
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(typename string_t::value_type), "Unsupported type");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline bool
|
||||
parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_string_literal_with_accel()
|
||||
{
|
||||
if constexpr (sizeof(*_cur) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (_end - _cur >= accel_traits::step) {
|
||||
auto pack = accel_traits::load_unaligned(&(*_cur));
|
||||
auto result = accel_traits::less(pack, 32);
|
||||
result =
|
||||
accel_traits::bitwise_or(result, accel_traits::equal(pack, static_cast<uint8_t>('"')));
|
||||
result =
|
||||
accel_traits::bitwise_or(result, accel_traits::equal(pack, static_cast<uint8_t>('\\')));
|
||||
|
||||
if (accel_traits::is_all_zero(result)) {
|
||||
_cur += accel_traits::step;
|
||||
}
|
||||
else {
|
||||
auto index = accel_traits::first_nonzero_byte(result);
|
||||
_cur += index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _cur != _end;
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_whitespace() noexcept
|
||||
{
|
||||
while (_cur != _end) {
|
||||
switch (*_cur) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
++_cur;
|
||||
break;
|
||||
case '/':
|
||||
if constexpr (accept_jsonc) {
|
||||
if (!skip_comment()) {
|
||||
return false;
|
||||
}
|
||||
// else continue;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
bool json::parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_comment() noexcept
|
||||
{
|
||||
if (_cur == _end || *_cur != '/') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (++_cur == _end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enum class comment_type
|
||||
{
|
||||
invalid,
|
||||
line,
|
||||
block,
|
||||
} t = comment_type::invalid;
|
||||
|
||||
switch (*_cur++) {
|
||||
case '/':
|
||||
t = comment_type::line;
|
||||
break;
|
||||
case '*':
|
||||
t = comment_type::block;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
while (_cur != _end) {
|
||||
switch (*_cur++) {
|
||||
case '\n':
|
||||
if (t == comment_type::line) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
if (t == comment_type::block && _cur != _end && *_cur == '/') {
|
||||
++_cur;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// _cur == _end
|
||||
return t == comment_type::line;
|
||||
}
|
||||
|
||||
template <bool accept_jsonc, typename string_t, typename parsing_t, typename accel_traits>
|
||||
inline bool parser<accept_jsonc, string_t, parsing_t, accel_traits>::skip_digit()
|
||||
{
|
||||
// At least one digit
|
||||
if (_cur != _end && std::isdigit(*_cur)) {
|
||||
++_cur;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (_cur != _end && std::isdigit(*_cur)) {
|
||||
++_cur;
|
||||
}
|
||||
|
||||
if (_cur != _end) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// *************************
|
||||
// * utils impl *
|
||||
// *************************
|
||||
|
||||
template <typename parsing_t>
|
||||
auto parse(const parsing_t& content)
|
||||
{
|
||||
using string_t = std::basic_string<typename parsing_t::value_type>;
|
||||
return parser<false, string_t, parsing_t>::parse(content);
|
||||
}
|
||||
|
||||
template <typename char_t>
|
||||
auto parse(char_t* content)
|
||||
{
|
||||
return parse(std::basic_string_view<std::decay_t<char_t>> { content });
|
||||
}
|
||||
|
||||
template <typename istream_t, typename _>
|
||||
auto parse(istream_t& ifs, bool check_bom, bool with_commets)
|
||||
{
|
||||
using string_t = std::basic_string<typename istream_t::char_type>;
|
||||
|
||||
ifs.seekg(0, std::ios::end);
|
||||
auto file_size = ifs.tellg();
|
||||
|
||||
ifs.seekg(0, std::ios::beg);
|
||||
string_t str(file_size, '\0');
|
||||
|
||||
ifs.read(str.data(), file_size);
|
||||
|
||||
if (check_bom) {
|
||||
using uchar = unsigned char;
|
||||
static constexpr uchar Bom_0 = 0xEF;
|
||||
static constexpr uchar Bom_1 = 0xBB;
|
||||
static constexpr uchar Bom_2 = 0xBF;
|
||||
|
||||
if (str.size() >= 3 && static_cast<uchar>(str.at(0)) == Bom_0
|
||||
&& static_cast<uchar>(str.at(1)) == Bom_1 && static_cast<uchar>(str.at(2)) == Bom_2) {
|
||||
str.assign(str.begin() + 3, str.end());
|
||||
}
|
||||
}
|
||||
return with_commets ? parsec(str) : parse(str);
|
||||
}
|
||||
|
||||
template <typename ifstream_t, typename path_t>
|
||||
auto open(const path_t& filepath, bool check_bom, bool with_commets)
|
||||
{
|
||||
using char_t = typename ifstream_t::char_type;
|
||||
using string_t = std::basic_string<char_t>;
|
||||
using json_t = json::basic_value<string_t>;
|
||||
using return_t = std::optional<json_t>;
|
||||
|
||||
ifstream_t ifs(filepath, std::ios::in);
|
||||
if (!ifs.is_open()) {
|
||||
return return_t(std::nullopt);
|
||||
}
|
||||
auto opt = parse(ifs, check_bom, with_commets);
|
||||
ifs.close();
|
||||
return opt;
|
||||
}
|
||||
|
||||
template <typename parsing_t>
|
||||
auto parsec(const parsing_t& content)
|
||||
{
|
||||
using string_t = std::basic_string<typename parsing_t::value_type>;
|
||||
return parser<true, string_t, parsing_t>::parse(content);
|
||||
}
|
||||
|
||||
template <typename char_t>
|
||||
auto parsec(char_t* content)
|
||||
{
|
||||
return parsec(std::basic_string_view<std::decay_t<char_t>> { content });
|
||||
}
|
||||
|
||||
namespace literals
|
||||
{
|
||||
inline value operator""_json(const char* str, size_t len)
|
||||
{
|
||||
return operator""_jvalue(str, len);
|
||||
}
|
||||
|
||||
inline wvalue operator""_json(const wchar_t* str, size_t len)
|
||||
{
|
||||
return operator""_jvalue(str, len);
|
||||
}
|
||||
|
||||
inline value operator""_jvalue(const char* str, size_t len)
|
||||
{
|
||||
return parse(std::string_view(str, len)).value_or(value());
|
||||
}
|
||||
|
||||
inline wvalue operator""_jvalue(const wchar_t* str, size_t len)
|
||||
{
|
||||
return parse(std::wstring_view(str, len)).value_or(wvalue());
|
||||
}
|
||||
|
||||
inline array operator""_jarray(const char* str, size_t len)
|
||||
{
|
||||
auto val = parse(std::string_view(str, len)).value_or(value());
|
||||
return val.is_array() ? val.as_array() : array();
|
||||
}
|
||||
|
||||
inline warray operator""_jarray(const wchar_t* str, size_t len)
|
||||
{
|
||||
auto val = parse(std::wstring_view(str, len)).value_or(wvalue());
|
||||
return val.is_array() ? val.as_array() : warray();
|
||||
}
|
||||
|
||||
inline object operator""_jobject(const char* str, size_t len)
|
||||
{
|
||||
auto val = parse(std::string_view(str, len)).value_or(value());
|
||||
return val.is_object() ? val.as_object() : object();
|
||||
}
|
||||
|
||||
inline wobject operator""_jobject(const wchar_t* str, size_t len)
|
||||
{
|
||||
auto val = parse(std::wstring_view(str, len)).value_or(wvalue());
|
||||
return val.is_object() ? val.as_object() : wobject();
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
template <typename string_t>
|
||||
const basic_value<string_t> invalid_value()
|
||||
{
|
||||
return basic_value<string_t>(
|
||||
basic_value<string_t>::value_type::invalid,
|
||||
typename basic_value<string_t>::var_t());
|
||||
}
|
||||
} // namespace json
|
||||
656
3rdparty/include/meojson/reflection/extensions.hpp
vendored
Normal file
656
3rdparty/include/meojson/reflection/extensions.hpp
vendored
Normal file
@@ -0,0 +1,656 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include "../common/types.hpp"
|
||||
|
||||
namespace json::ext
|
||||
{
|
||||
|
||||
template <typename string_t, typename impl_t, typename var_t, size_t len> // (size_t)-1 for no
|
||||
// restriction
|
||||
class __jsonization_array
|
||||
{
|
||||
public:
|
||||
json::basic_value<string_t> to_json(const var_t& value) const
|
||||
{
|
||||
return static_cast<const impl_t*>(this)->to_json_array(value);
|
||||
}
|
||||
|
||||
bool check_json(const json::basic_value<string_t>& json) const
|
||||
{
|
||||
if (!json.is_array()) {
|
||||
return false;
|
||||
}
|
||||
const auto& arr = json.as_array();
|
||||
if constexpr (len != static_cast<size_t>(-1)) {
|
||||
if (len != arr.size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return static_cast<const impl_t*>(this)->check_json_array(arr);
|
||||
}
|
||||
|
||||
bool from_json(const json::basic_value<string_t>& json, var_t& value) const
|
||||
{
|
||||
if (!json.is_array()) {
|
||||
return false;
|
||||
}
|
||||
const auto& arr = json.as_array();
|
||||
if constexpr (len != static_cast<size_t>(-1)) {
|
||||
if (len != arr.size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return static_cast<const impl_t*>(this)->from_json_array(arr, value);
|
||||
}
|
||||
|
||||
json::basic_value<string_t> move_to_json(var_t value) const
|
||||
{
|
||||
return static_cast<const impl_t*>(this)->move_to_json_array(std::move(value));
|
||||
}
|
||||
|
||||
bool move_from_json(json::basic_value<string_t> json, var_t& value) const
|
||||
{
|
||||
if (!json.is_array()) {
|
||||
return false;
|
||||
}
|
||||
auto& arr = json.as_array();
|
||||
if constexpr (len != static_cast<size_t>(-1)) {
|
||||
if (len != arr.size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return static_cast<const impl_t*>(this)->move_from_json_array(std::move(arr), value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename string_t, typename impl_t, typename var_t>
|
||||
class __jsonization_object
|
||||
{
|
||||
public:
|
||||
json::basic_value<string_t> to_json(const var_t& value) const
|
||||
{
|
||||
return static_cast<const impl_t*>(this)->to_json_object(value);
|
||||
}
|
||||
|
||||
bool check_json(const json::basic_value<string_t>& json) const
|
||||
{
|
||||
if (!json.is_object()) {
|
||||
return false;
|
||||
}
|
||||
const auto& obj = json.as_object();
|
||||
return static_cast<const impl_t*>(this)->check_json_object(obj);
|
||||
}
|
||||
|
||||
bool from_json(const json::basic_value<string_t>& json, var_t& value) const
|
||||
{
|
||||
if (!json.is_object()) {
|
||||
return false;
|
||||
}
|
||||
const auto& obj = json.as_object();
|
||||
return static_cast<const impl_t*>(this)->from_json_object(obj, value);
|
||||
}
|
||||
|
||||
json::basic_value<string_t> move_to_json(var_t value) const
|
||||
{
|
||||
return static_cast<const impl_t*>(this)->move_to_json_object(std::move(value));
|
||||
}
|
||||
|
||||
bool move_from_json(json::basic_value<string_t> json, var_t& value) const
|
||||
{
|
||||
if (!json.is_object()) {
|
||||
return false;
|
||||
}
|
||||
auto& obj = json.as_object();
|
||||
return static_cast<const impl_t*>(this)->move_from_json_object(std::move(obj), value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename string_t>
|
||||
class jsonization<string_t, std::nullptr_t>
|
||||
{
|
||||
public:
|
||||
json::basic_value<string_t> to_json(const std::nullptr_t&) const
|
||||
{
|
||||
return json::basic_value<string_t> {};
|
||||
}
|
||||
|
||||
bool check_json(const json::basic_value<string_t>& json) const { return json.is_null(); }
|
||||
|
||||
bool from_json(const json::basic_value<string_t>& json, std::nullptr_t&)
|
||||
{
|
||||
return check_json(json);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename string_t>
|
||||
class jsonization<
|
||||
string_t,
|
||||
std::filesystem::path,
|
||||
std::enable_if_t<
|
||||
std::is_same_v<string_t, std::filesystem::path::string_type>
|
||||
|| std::is_same_v<string_t, std::string>>>
|
||||
{
|
||||
public:
|
||||
json::basic_value<string_t> to_json(const std::filesystem::path& path) const
|
||||
{
|
||||
if constexpr (std::is_same_v<string_t, std::filesystem::path::string_type>) {
|
||||
return path.native();
|
||||
}
|
||||
else if constexpr (std::is_same_v<string_t, std::string>) {
|
||||
#if __cplusplus >= 202002L
|
||||
std::u8string u8str = path.u8string();
|
||||
return std::string { u8str.begin(), u8str.end() };
|
||||
#else
|
||||
return path.u8string();
|
||||
#endif
|
||||
}
|
||||
#if __cplusplus >= 202002L
|
||||
else if constexpr (std::is_same_v<string_t, std::u8string>) {
|
||||
return path.u8string();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool check_json(const json::basic_value<string_t>& json) const { return json.is_string(); }
|
||||
|
||||
bool from_json(const json::basic_value<string_t>& json, std::filesystem::path& path) const
|
||||
{
|
||||
path = json.as_string();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
typename string_t,
|
||||
template <typename, size_t> typename arr_t,
|
||||
typename value_t,
|
||||
size_t size>
|
||||
class jsonization<string_t, arr_t<value_t, size>>
|
||||
: public __jsonization_array<
|
||||
string_t,
|
||||
jsonization<string_t, arr_t<value_t, size>>,
|
||||
arr_t<value_t, size>,
|
||||
size>
|
||||
{
|
||||
public:
|
||||
json::basic_array<string_t> to_json_array(const arr_t<value_t, size>& value) const
|
||||
{
|
||||
json::basic_array<string_t> result;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
result.emplace_back(value.at(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool check_json_array(const json::basic_array<string_t>& arr) const
|
||||
{
|
||||
return arr.template all<value_t>();
|
||||
}
|
||||
|
||||
bool from_json_array(const json::basic_array<string_t>& arr, arr_t<value_t, size>& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
value.at(i) = arr[i].template as<value_t>();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
json::basic_array<string_t> move_to_json_array(arr_t<value_t, size> value) const
|
||||
{
|
||||
json::basic_array<string_t> result;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
result.emplace_back(std::move(value.at(i)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool move_from_json_array(json::basic_array<string_t> arr, arr_t<value_t, size>& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
value.at(i) = std::move(arr[i]).template as<value_t>();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename string_t, typename collection_t>
|
||||
class jsonization<string_t, collection_t, std::enable_if_t<_utils::is_collection<collection_t>>>
|
||||
: public __jsonization_array<
|
||||
string_t,
|
||||
jsonization<string_t, collection_t>,
|
||||
collection_t,
|
||||
(size_t)-1>
|
||||
{
|
||||
public:
|
||||
json::basic_array<string_t> to_json_array(const collection_t& value) const
|
||||
{
|
||||
json::basic_array<string_t> result;
|
||||
for (const auto& val : value) {
|
||||
result.emplace_back(val);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool check_json_array(const json::basic_array<string_t>& arr) const
|
||||
{
|
||||
return arr.template all<typename collection_t::value_type>();
|
||||
}
|
||||
|
||||
bool from_json_array(const json::basic_array<string_t>& arr, collection_t& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
value = {};
|
||||
for (const auto& val : arr) {
|
||||
if constexpr (_utils::has_emplace_back<collection_t>::value) {
|
||||
value.emplace_back(val.template as<typename collection_t::value_type>());
|
||||
}
|
||||
else {
|
||||
value.emplace(val.template as<typename collection_t::value_type>());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
json::basic_array<string_t> move_to_json_array(collection_t value) const
|
||||
{
|
||||
json::basic_array<string_t> result;
|
||||
for (auto& val : value) {
|
||||
result.emplace_back(std::move(val));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool move_from_json_array(json::basic_array<string_t> arr, collection_t& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& val : arr) {
|
||||
if constexpr (_utils::has_emplace_back<collection_t>::value) {
|
||||
value.emplace_back(std::move(val).template as<typename collection_t::value_type>());
|
||||
}
|
||||
else {
|
||||
value.emplace(std::move(val).template as<typename collection_t::value_type>());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename string_t, template <typename...> typename tuple_t, typename... args_t>
|
||||
class jsonization<
|
||||
string_t,
|
||||
tuple_t<args_t...>,
|
||||
std::enable_if_t<_utils::is_tuple_like<tuple_t<args_t...>>>>
|
||||
: public __jsonization_array<
|
||||
string_t,
|
||||
jsonization<string_t, tuple_t<args_t...>>,
|
||||
tuple_t<args_t...>,
|
||||
std::tuple_size_v<tuple_t<args_t...>>>
|
||||
{
|
||||
public:
|
||||
constexpr static size_t tuple_size = std::tuple_size_v<tuple_t<args_t...>>;
|
||||
|
||||
json::basic_array<string_t> to_json_array(const tuple_t<args_t...>& value) const
|
||||
{
|
||||
json::basic_array<string_t> result;
|
||||
to_json_impl(result, value, std::make_index_sequence<tuple_size>());
|
||||
return result;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void to_json_impl(
|
||||
json::basic_array<string_t>& arr,
|
||||
const tuple_t<args_t...>& t,
|
||||
std::index_sequence<Is...>) const
|
||||
{
|
||||
using std::get;
|
||||
(arr.emplace_back(get<Is>(t)), ...);
|
||||
}
|
||||
|
||||
bool check_json_array(const json::basic_array<string_t>& arr) const
|
||||
{
|
||||
return check_json_impl(arr, std::make_index_sequence<tuple_size>());
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
bool check_json_impl(const json::basic_array<string_t>& arr, std::index_sequence<Is...>) const
|
||||
{
|
||||
return (arr[Is].template is<std::tuple_element_t<Is, tuple_t<args_t...>>>() && ...);
|
||||
}
|
||||
|
||||
bool from_json_array(const json::basic_array<string_t>& arr, tuple_t<args_t...>& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
from_json_impl(arr, value, std::make_index_sequence<tuple_size>());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void from_json_impl(
|
||||
const json::basic_array<string_t>& arr,
|
||||
tuple_t<args_t...>& t,
|
||||
std::index_sequence<Is...>) const
|
||||
{
|
||||
using std::get;
|
||||
((get<Is>(t) = arr[Is].template as<std::tuple_element_t<Is, tuple_t<args_t...>>>()), ...);
|
||||
}
|
||||
|
||||
json::basic_array<string_t> move_to_json_array(tuple_t<args_t...> value) const
|
||||
{
|
||||
json::basic_array<string_t> result;
|
||||
move_to_json_impl(result, std::move(value), std::make_index_sequence<tuple_size>());
|
||||
return result;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void move_to_json_impl(
|
||||
json::basic_array<string_t>& arr,
|
||||
tuple_t<args_t...> t,
|
||||
std::index_sequence<Is...>) const
|
||||
{
|
||||
using std::get;
|
||||
(arr.emplace_back(std::move(get<Is>(t))), ...);
|
||||
}
|
||||
|
||||
bool move_from_json_array(json::basic_array<string_t> arr, tuple_t<args_t...>& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
move_from_json_impl(arr, value, std::make_index_sequence<tuple_size>());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void move_from_json_impl(
|
||||
json::basic_array<string_t> arr,
|
||||
tuple_t<args_t...>& t,
|
||||
std::index_sequence<Is...>) const
|
||||
{
|
||||
using std::get;
|
||||
((get<Is>(t) =
|
||||
std::move(arr[Is]).template as<std::tuple_element_t<Is, tuple_t<args_t...>>>()),
|
||||
...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename string_t, typename map_t>
|
||||
class jsonization<
|
||||
string_t,
|
||||
map_t,
|
||||
std::enable_if_t<_utils::is_map<map_t> && std::is_same_v<typename map_t::key_type, string_t>>>
|
||||
: public __jsonization_object<string_t, jsonization<string_t, map_t>, map_t>
|
||||
{
|
||||
public:
|
||||
json::basic_object<string_t> to_json_object(const map_t& value) const
|
||||
{
|
||||
json::basic_object<string_t> result;
|
||||
for (const auto& [key, val] : value) {
|
||||
result.emplace(key, val);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool check_json_object(const json::basic_object<string_t>& arr) const
|
||||
{
|
||||
for (const auto& [key, val] : arr) {
|
||||
if (!val.template is<typename map_t::mapped_type>()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool from_json_object(const json::basic_object<string_t>& arr, map_t& value) const
|
||||
{
|
||||
// TODO: 是不是直接from不check了算了
|
||||
if (!check_json_object(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
value = {};
|
||||
for (const auto& [key, val] : arr) {
|
||||
value.emplace(key, val.template as<typename map_t::mapped_type>());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
json::basic_object<string_t> move_to_json_object(map_t value) const
|
||||
{
|
||||
json::basic_object<string_t> result;
|
||||
for (auto& [key, val] : value) {
|
||||
result.emplace(key, std::move(val));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool move_from_json_object(json::basic_object<string_t> arr, map_t& value) const
|
||||
{
|
||||
// TODO: 是不是直接from不check了算了
|
||||
if (!check_json_object(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
value = {};
|
||||
for (auto& [key, val] : arr) {
|
||||
value.emplace(key, std::move(val).template as<typename map_t::mapped_type>());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename string_t, typename... args_t>
|
||||
class jsonization<string_t, std::variant<args_t...>>
|
||||
{
|
||||
public:
|
||||
using variant_t = std::variant<args_t...>;
|
||||
constexpr static size_t variant_size = std::variant_size_v<variant_t>;
|
||||
|
||||
json::basic_value<string_t> to_json(const variant_t& value) const
|
||||
{
|
||||
json::basic_value<string_t> result;
|
||||
to_json_impl(result, value, std::make_index_sequence<variant_size>());
|
||||
return result;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void to_json_impl(
|
||||
json::basic_value<string_t>& val,
|
||||
const variant_t& t,
|
||||
std::index_sequence<Is...>) const
|
||||
{
|
||||
using std::get;
|
||||
std::ignore = ((t.index() == Is ? (val = get<Is>(t), true) : false) || ...);
|
||||
}
|
||||
|
||||
bool check_json(const json::basic_value<string_t>& json) const
|
||||
{
|
||||
return check_json_impl(json, std::make_index_sequence<variant_size>());
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
bool check_json_impl(const json::basic_value<string_t>& val, std::index_sequence<Is...>) const
|
||||
{
|
||||
return (val.template is<std::variant_alternative_t<Is, variant_t>>() || ...);
|
||||
}
|
||||
|
||||
bool from_json(const json::basic_value<string_t>& json, variant_t& value) const
|
||||
{
|
||||
if (!check_json_impl(json, std::make_index_sequence<variant_size>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
from_json_impl(json, value, std::make_index_sequence<variant_size>());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void from_json_impl(
|
||||
const json::basic_value<string_t>& json,
|
||||
variant_t& t,
|
||||
std::index_sequence<Is...>) const
|
||||
{
|
||||
std::ignore =
|
||||
((json.template is<std::variant_alternative_t<Is, variant_t>>()
|
||||
? (t = json.template as<std::variant_alternative_t<Is, variant_t>>(), true)
|
||||
: false)
|
||||
|| ...);
|
||||
}
|
||||
|
||||
json::basic_value<string_t> move_to_json(variant_t value) const
|
||||
{
|
||||
json::basic_value<string_t> result;
|
||||
move_to_json_impl(result, std::move(value), std::make_index_sequence<variant_size>());
|
||||
return result;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void
|
||||
move_to_json_impl(json::basic_value<string_t>& val, variant_t t, std::index_sequence<Is...>)
|
||||
const
|
||||
{
|
||||
using std::get;
|
||||
std::ignore = ((t.index() == Is ? (val = std::move(get<Is>(t)), true) : false) || ...);
|
||||
}
|
||||
|
||||
bool move_from_json(json::basic_value<string_t> json, variant_t& value) const
|
||||
{
|
||||
if (!check_json_impl(json, std::make_index_sequence<variant_size>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
move_from_json_impl(std::move(json), value, std::make_index_sequence<variant_size>());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
void move_from_json_impl(
|
||||
json::basic_value<string_t> json,
|
||||
variant_t& t,
|
||||
std::index_sequence<Is...>) const
|
||||
{
|
||||
std::ignore =
|
||||
((json.template is<std::variant_alternative_t<Is, variant_t>>()
|
||||
? (t = std::move(json).template as<std::variant_alternative_t<Is, variant_t>>(),
|
||||
true)
|
||||
: false)
|
||||
|| ...);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: check if has move_xxx in member
|
||||
template <typename string_t, typename var_t>
|
||||
class jsonization<
|
||||
string_t,
|
||||
var_t,
|
||||
std::enable_if_t<
|
||||
_utils::has_to_json_in_member<var_t>::value
|
||||
&& _utils::has_check_json_in_member<var_t, string_t>::value
|
||||
&& _utils::has_from_json_in_member<var_t, string_t>::value>>
|
||||
{
|
||||
public:
|
||||
json::basic_value<string_t> to_json(const var_t& value) const { return value.to_json(); }
|
||||
|
||||
bool check_json(const json::basic_value<string_t>& json) const
|
||||
{
|
||||
var_t value;
|
||||
return value.check_json(json);
|
||||
}
|
||||
|
||||
bool from_json(const json::basic_value<string_t>& json, var_t& value) const
|
||||
{
|
||||
return value.from_json(json);
|
||||
}
|
||||
|
||||
json::basic_value<string_t> move_to_json(var_t value) const { return to_json(value); }
|
||||
|
||||
bool move_from_json(json::basic_value<string_t> json, var_t& value) const
|
||||
{
|
||||
return from_json(json, value);
|
||||
}
|
||||
};
|
||||
|
||||
// really need this fucking queue?
|
||||
template <typename string_t, typename value_t>
|
||||
class jsonization<string_t, std::queue<value_t>>
|
||||
: public __jsonization_array<
|
||||
string_t,
|
||||
jsonization<string_t, std::queue<value_t>>,
|
||||
std::queue<value_t>,
|
||||
(size_t)-1>
|
||||
{
|
||||
public:
|
||||
json::basic_array<string_t> to_json_array(const std::queue<value_t>& value) const
|
||||
{
|
||||
return move_to_json_array(value);
|
||||
}
|
||||
|
||||
bool check_json_array(const json::basic_array<string_t>& arr) const
|
||||
{
|
||||
return arr.template all<value_t>();
|
||||
}
|
||||
|
||||
bool from_json_array(const json::basic_array<string_t>& arr, std::queue<value_t>& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
value = {};
|
||||
for (const auto& val : arr) {
|
||||
value.emplace(val.template as<value_t>());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
json::basic_array<string_t> move_to_json_array(std::queue<value_t> value) const
|
||||
{
|
||||
json::basic_array<string_t> result;
|
||||
while (!value.empty()) {
|
||||
result.emplace_back(std::move(value.front()));
|
||||
value.pop();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool move_from_json_array(json::basic_array<string_t> arr, std::queue<value_t>& value) const
|
||||
{
|
||||
if (!check_json_array(arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& val : arr) {
|
||||
value.emplace(std::move(val).template as<value_t>());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
648
3rdparty/include/meojson/reflection/jsonization.hpp
vendored
Normal file
648
3rdparty/include/meojson/reflection/jsonization.hpp
vendored
Normal file
@@ -0,0 +1,648 @@
|
||||
// IWYU pragma: private, include <meojson/json.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../common/types.hpp"
|
||||
#include "extensions.hpp"
|
||||
|
||||
namespace json::_jsonization_helper
|
||||
{
|
||||
|
||||
template <typename value_t>
|
||||
struct is_optional_t : public std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename value_t>
|
||||
struct is_optional_t<std::optional<value_t>> : public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename value_t>
|
||||
inline constexpr bool is_optional_v = is_optional_t<value_t>::value;
|
||||
|
||||
struct next_is_optional_t
|
||||
{
|
||||
};
|
||||
|
||||
struct next_override_key_t
|
||||
{
|
||||
const char* key;
|
||||
};
|
||||
|
||||
struct next_state_t
|
||||
{
|
||||
bool is_optional = false;
|
||||
const char* override_key = nullptr;
|
||||
};
|
||||
|
||||
struct va_arg_end
|
||||
{
|
||||
};
|
||||
|
||||
template <typename tag_t>
|
||||
struct is_tag_t : public std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_tag_t<next_is_optional_t> : public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_tag_t<next_override_key_t> : public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
struct dumper
|
||||
{
|
||||
void _to_json(json::object&, va_arg_end) const {}
|
||||
|
||||
template <typename... rest_t>
|
||||
void _to_json(json::object& result, const char* key, rest_t&&... rest) const
|
||||
{
|
||||
_to_json(result, next_state_t {}, key, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <
|
||||
typename var_t,
|
||||
typename... rest_t,
|
||||
typename _ = std::enable_if_t<!is_tag_t<var_t>::value, void>>
|
||||
void _to_json(
|
||||
json::object& result,
|
||||
next_state_t state,
|
||||
const char* key,
|
||||
const var_t& var,
|
||||
rest_t&&... rest) const
|
||||
{
|
||||
if (state.override_key) {
|
||||
key = state.override_key;
|
||||
}
|
||||
if constexpr (is_optional_v<var_t>) {
|
||||
if (!state.is_optional) {
|
||||
throw exception("std::optional must be used with MEO_OPT");
|
||||
}
|
||||
|
||||
if (var.has_value()) {
|
||||
result.emplace(key, var.value());
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.emplace(key, var);
|
||||
}
|
||||
_to_json(result, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... rest_t>
|
||||
void _to_json(
|
||||
json::object& result,
|
||||
next_state_t state,
|
||||
const char*,
|
||||
next_is_optional_t,
|
||||
rest_t&&... rest) const
|
||||
{
|
||||
state.is_optional = true;
|
||||
_to_json(result, state, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... rest_t>
|
||||
void _to_json(
|
||||
json::object& result,
|
||||
next_state_t state,
|
||||
const char*,
|
||||
next_override_key_t override_key,
|
||||
rest_t&&... rest) const
|
||||
{
|
||||
state.override_key = override_key.key;
|
||||
_to_json(result, state, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
};
|
||||
|
||||
struct checker
|
||||
{
|
||||
bool _check_json(const json::value&, std::string&, va_arg_end) const { return true; }
|
||||
|
||||
template <typename... rest_t>
|
||||
bool _check_json(
|
||||
const json::value& in,
|
||||
std::string& error_key,
|
||||
const char* key,
|
||||
rest_t&&... rest) const
|
||||
{
|
||||
return _check_json(in, error_key, next_state_t {}, key, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <
|
||||
typename var_t,
|
||||
typename... rest_t,
|
||||
typename _ = std::enable_if_t<!is_tag_t<var_t>::value, void>>
|
||||
bool _check_json(
|
||||
const json::value& in,
|
||||
std::string& error_key,
|
||||
next_state_t state,
|
||||
const char* key,
|
||||
const var_t&,
|
||||
rest_t&&... rest) const
|
||||
{
|
||||
if (state.override_key) {
|
||||
key = state.override_key;
|
||||
}
|
||||
auto opt = in.find(key);
|
||||
if constexpr (is_optional_v<var_t>) {
|
||||
if (!state.is_optional) {
|
||||
throw exception("std::optional must be used with MEO_OPT");
|
||||
}
|
||||
|
||||
if (opt && !opt->is<typename var_t::value_type>()) {
|
||||
error_key = key;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (state.is_optional) {
|
||||
if (opt && !opt->is<var_t>()) {
|
||||
error_key = key;
|
||||
return false;
|
||||
} // is_optional, ignore key not found
|
||||
}
|
||||
else if (!opt || !opt->is<var_t>()) {
|
||||
error_key = key;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return _check_json(in, error_key, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... rest_t>
|
||||
bool _check_json(
|
||||
const json::value& in,
|
||||
std::string& error_key,
|
||||
next_state_t state,
|
||||
const char*,
|
||||
next_is_optional_t,
|
||||
rest_t&&... rest) const
|
||||
{
|
||||
state.is_optional = true;
|
||||
return _check_json(in, error_key, state, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... rest_t>
|
||||
bool _check_json(
|
||||
const json::value& in,
|
||||
std::string& error_key,
|
||||
next_state_t state,
|
||||
const char*,
|
||||
next_override_key_t override_key,
|
||||
rest_t&&... rest) const
|
||||
{
|
||||
state.override_key = override_key.key;
|
||||
return _check_json(in, error_key, state, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
};
|
||||
|
||||
struct loader
|
||||
{
|
||||
bool _from_json(const json::value&, std::string&, va_arg_end) const { return true; }
|
||||
|
||||
template <typename... rest_t>
|
||||
bool
|
||||
_from_json(const json::value& in, std::string& error_key, const char* key, rest_t&&... rest)
|
||||
{
|
||||
return _from_json(in, error_key, next_state_t {}, key, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <
|
||||
typename var_t,
|
||||
typename... rest_t,
|
||||
typename _ = std::enable_if_t<!is_tag_t<var_t>::value, void>>
|
||||
bool _from_json(
|
||||
const json::value& in,
|
||||
std::string& error_key,
|
||||
next_state_t state,
|
||||
const char* key,
|
||||
var_t& var,
|
||||
rest_t&&... rest)
|
||||
{
|
||||
if (state.override_key) {
|
||||
key = state.override_key;
|
||||
}
|
||||
auto opt = in.find(key);
|
||||
if constexpr (is_optional_v<var_t>) {
|
||||
if (!state.is_optional) {
|
||||
throw exception("std::optional must be used with MEO_OPT");
|
||||
}
|
||||
|
||||
if (opt && !opt->is<typename var_t::value_type>()) {
|
||||
error_key = key;
|
||||
return false;
|
||||
}
|
||||
if (opt) {
|
||||
var = std::move(opt)->as<typename var_t::value_type>();
|
||||
}
|
||||
else {
|
||||
var = std::nullopt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (state.is_optional) {
|
||||
if (opt && !opt->is<var_t>()) {
|
||||
error_key = key;
|
||||
return false;
|
||||
} // is_optional, ignore key not found
|
||||
}
|
||||
else if (!opt || !opt->is<var_t>()) {
|
||||
error_key = key;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt) {
|
||||
var = std::move(opt)->as<var_t>();
|
||||
}
|
||||
}
|
||||
|
||||
return _from_json(in, error_key, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... rest_t>
|
||||
bool _from_json(
|
||||
const json::value& in,
|
||||
std::string& error_key,
|
||||
next_state_t state,
|
||||
const char*,
|
||||
next_is_optional_t,
|
||||
rest_t&&... rest)
|
||||
{
|
||||
state.is_optional = true;
|
||||
return _from_json(in, error_key, state, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... rest_t>
|
||||
bool _from_json(
|
||||
const json::value& in,
|
||||
std::string& error_key,
|
||||
next_state_t state,
|
||||
const char*,
|
||||
next_override_key_t override_key,
|
||||
rest_t&&... rest)
|
||||
{
|
||||
state.override_key = override_key.key;
|
||||
return _from_json(in, error_key, state, std::forward<rest_t>(rest)...);
|
||||
}
|
||||
};
|
||||
} // namespace json::_jsonization_helper
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||
#endif
|
||||
|
||||
namespace json::_private_macro
|
||||
{
|
||||
#define _MEOJSON_STRINGIZE(arg) _MEOJSON_STRINGIZE1(arg)
|
||||
#define _MEOJSON_STRINGIZE1(arg) _MEOJSON_STRINGIZE2(arg)
|
||||
#define _MEOJSON_STRINGIZE2(arg) #arg
|
||||
|
||||
#define _MEOJSON_CONCATENATE(arg1, arg2) _MEOJSON_CONCATENATE1(arg1, arg2)
|
||||
#define _MEOJSON_CONCATENATE1(arg1, arg2) _MEOJSON_CONCATENATE2(arg1, arg2)
|
||||
#define _MEOJSON_CONCATENATE2(arg1, arg2) arg1##arg2
|
||||
|
||||
#define _MEOJSON_EXPAND(x) x
|
||||
|
||||
#define _MEOJSON_FOR_EACH_1(pred, x) pred(x)
|
||||
#define _MEOJSON_FOR_EACH_2(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_1(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_3(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_2(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_4(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_3(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_5(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_4(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_6(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_5(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_7(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_6(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_8(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_7(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_9(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_8(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_10(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_9(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_11(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_10(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_12(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_11(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_13(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_12(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_14(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_13(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_15(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_14(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_16(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_15(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_17(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_16(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_18(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_17(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_19(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_18(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_20(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_19(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_21(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_20(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_22(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_21(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_23(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_22(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_24(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_23(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_25(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_24(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_26(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_25(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_27(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_26(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_28(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_27(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_29(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_28(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_30(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_29(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_31(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_30(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_32(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_31(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_33(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_32(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_34(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_33(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_35(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_34(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_36(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_35(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_37(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_36(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_38(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_37(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_39(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_38(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_40(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_39(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_41(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_40(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_42(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_41(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_43(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_42(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_44(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_43(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_45(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_44(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_46(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_45(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_47(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_46(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_48(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_47(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_49(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_48(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_50(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_49(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_51(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_50(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_52(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_51(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_53(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_52(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_54(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_53(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_55(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_54(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_56(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_55(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_57(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_56(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_58(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_57(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_59(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_58(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_60(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_59(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_61(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_60(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_62(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_61(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_63(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_62(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH_64(pred, x, ...) \
|
||||
pred(x) _MEOJSON_EXPAND(_MEOJSON_FOR_EACH_63(pred, __VA_ARGS__))
|
||||
|
||||
#define _MEOJSON_ARG_COUNT(...) \
|
||||
_MEOJSON_EXPAND(_MEOJSON_ARG_COUNT1( \
|
||||
0, \
|
||||
##__VA_ARGS__, \
|
||||
64, \
|
||||
63, \
|
||||
62, \
|
||||
61, \
|
||||
60, \
|
||||
59, \
|
||||
58, \
|
||||
57, \
|
||||
56, \
|
||||
55, \
|
||||
54, \
|
||||
53, \
|
||||
52, \
|
||||
51, \
|
||||
50, \
|
||||
49, \
|
||||
48, \
|
||||
47, \
|
||||
46, \
|
||||
45, \
|
||||
44, \
|
||||
43, \
|
||||
42, \
|
||||
41, \
|
||||
40, \
|
||||
39, \
|
||||
38, \
|
||||
37, \
|
||||
36, \
|
||||
35, \
|
||||
34, \
|
||||
33, \
|
||||
32, \
|
||||
31, \
|
||||
30, \
|
||||
29, \
|
||||
28, \
|
||||
27, \
|
||||
26, \
|
||||
25, \
|
||||
24, \
|
||||
23, \
|
||||
22, \
|
||||
21, \
|
||||
20, \
|
||||
19, \
|
||||
18, \
|
||||
17, \
|
||||
16, \
|
||||
15, \
|
||||
14, \
|
||||
13, \
|
||||
12, \
|
||||
11, \
|
||||
10, \
|
||||
9, \
|
||||
8, \
|
||||
7, \
|
||||
6, \
|
||||
5, \
|
||||
4, \
|
||||
3, \
|
||||
2, \
|
||||
1, \
|
||||
0))
|
||||
#define _MEOJSON_ARG_COUNT1( \
|
||||
_0, \
|
||||
_1, \
|
||||
_2, \
|
||||
_3, \
|
||||
_4, \
|
||||
_5, \
|
||||
_6, \
|
||||
_7, \
|
||||
_8, \
|
||||
_9, \
|
||||
_10, \
|
||||
_11, \
|
||||
_12, \
|
||||
_13, \
|
||||
_14, \
|
||||
_15, \
|
||||
_16, \
|
||||
_17, \
|
||||
_18, \
|
||||
_19, \
|
||||
_20, \
|
||||
_21, \
|
||||
_22, \
|
||||
_23, \
|
||||
_24, \
|
||||
_25, \
|
||||
_26, \
|
||||
_27, \
|
||||
_28, \
|
||||
_29, \
|
||||
_30, \
|
||||
_31, \
|
||||
_32, \
|
||||
_33, \
|
||||
_34, \
|
||||
_35, \
|
||||
_36, \
|
||||
_37, \
|
||||
_38, \
|
||||
_39, \
|
||||
_40, \
|
||||
_41, \
|
||||
_42, \
|
||||
_43, \
|
||||
_44, \
|
||||
_45, \
|
||||
_46, \
|
||||
_47, \
|
||||
_48, \
|
||||
_49, \
|
||||
_50, \
|
||||
_51, \
|
||||
_52, \
|
||||
_53, \
|
||||
_54, \
|
||||
_55, \
|
||||
_56, \
|
||||
_57, \
|
||||
_58, \
|
||||
_59, \
|
||||
_60, \
|
||||
_61, \
|
||||
_62, \
|
||||
_63, \
|
||||
_64, \
|
||||
N, \
|
||||
...) \
|
||||
N
|
||||
|
||||
#define _MEOJSON_FOR_EACH_(N, pred, ...) \
|
||||
_MEOJSON_EXPAND(_MEOJSON_CONCATENATE(_MEOJSON_FOR_EACH_, N)(pred, __VA_ARGS__))
|
||||
#define _MEOJSON_FOR_EACH(pred, ...) \
|
||||
_MEOJSON_EXPAND( \
|
||||
_MEOJSON_FOR_EACH_(_MEOJSON_EXPAND(_MEOJSON_ARG_COUNT(__VA_ARGS__)), pred, __VA_ARGS__))
|
||||
|
||||
#define _MEOJSON_VARNAME(x) _MEOJSON_CONCATENATE(_meojson_jsonization_, x)
|
||||
#define _MEOJSON_KEY_VALUE(x) _MEOJSON_STRINGIZE(x), x,
|
||||
} // namespace json::_private_macro
|
||||
|
||||
#define MEO_TOJSON(...) \
|
||||
json::value to_json() const \
|
||||
{ \
|
||||
json::object result; \
|
||||
json::_jsonization_helper::dumper()._to_json( \
|
||||
result, \
|
||||
_MEOJSON_EXPAND(_MEOJSON_FOR_EACH(_MEOJSON_KEY_VALUE, __VA_ARGS__)) \
|
||||
json::_jsonization_helper::va_arg_end {}); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define MEO_CHECKJSON(...) \
|
||||
bool check_json(const json::value& _MEOJSON_VARNAME(in)) const \
|
||||
{ \
|
||||
std::string _MEOJSON_VARNAME(error_key); \
|
||||
return check_json(_MEOJSON_VARNAME(in), _MEOJSON_VARNAME(error_key)); \
|
||||
} \
|
||||
bool check_json( \
|
||||
const json::value& _MEOJSON_VARNAME(in), \
|
||||
std::string& _MEOJSON_VARNAME(error_key)) const \
|
||||
{ \
|
||||
return json::_jsonization_helper::checker()._check_json( \
|
||||
_MEOJSON_VARNAME(in), \
|
||||
_MEOJSON_VARNAME(error_key), \
|
||||
_MEOJSON_EXPAND(_MEOJSON_FOR_EACH(_MEOJSON_KEY_VALUE, __VA_ARGS__)) \
|
||||
json::_jsonization_helper::va_arg_end {}); \
|
||||
}
|
||||
|
||||
#define MEO_FROMJSON(...) \
|
||||
bool from_json(const json::value& _MEOJSON_VARNAME(in)) \
|
||||
{ \
|
||||
std::string _MEOJSON_VARNAME(error_key); \
|
||||
return from_json(_MEOJSON_VARNAME(in), _MEOJSON_VARNAME(error_key)); \
|
||||
} \
|
||||
bool from_json( \
|
||||
const json::value& _MEOJSON_VARNAME(in), \
|
||||
std::string& _MEOJSON_VARNAME(error_key)) \
|
||||
{ \
|
||||
return json::_jsonization_helper::loader()._from_json( \
|
||||
_MEOJSON_VARNAME(in), \
|
||||
_MEOJSON_VARNAME(error_key), \
|
||||
_MEOJSON_EXPAND(_MEOJSON_FOR_EACH(_MEOJSON_KEY_VALUE, __VA_ARGS__)) \
|
||||
json::_jsonization_helper::va_arg_end {}); \
|
||||
}
|
||||
|
||||
#define MEO_JSONIZATION(...) \
|
||||
_MEOJSON_EXPAND(MEO_TOJSON(__VA_ARGS__)) \
|
||||
_MEOJSON_EXPAND(MEO_CHECKJSON(__VA_ARGS__)) \
|
||||
_MEOJSON_EXPAND(MEO_FROMJSON(__VA_ARGS__))
|
||||
|
||||
#define MEO_OPT json::_jsonization_helper::next_is_optional_t {},
|
||||
#define MEO_KEY(key) json::_jsonization_helper::next_override_key_t { key },
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop // -Wgnu-zero-variadic-macro-arguments
|
||||
#endif
|
||||
293
CHANGELOG.md
293
CHANGELOG.md
@@ -1,268 +1,49 @@
|
||||
## v6.3.2
|
||||
|
||||
### 拉电线不知天地为何物 | Highlight
|
||||
|
||||
本次版本更新真的是千呼万唤始出来,也恰逢新年版本和 PC 端的发布,我们在这个版本提供了对 PC 端的初步支持,也合并了 SideStory 「辞岁行」 的数据。
|
||||
|
||||
#### Windows 端一键长草任务配置重构
|
||||
|
||||
本次更新我们对 Windows 端 「一键长草」 任务配置进行了重构,解决了一些痛点。
|
||||
|
||||
现在牛牛支持添加多个重复类型任务,并支持重命名。现在你可以通过 「一键长草」 任务左下角的加号按钮添加多个同类型任务,并可以通过拖拽任务来调整任务执行顺序,以及右键点击任务右侧的齿轮图标重命名和删除任务,这样你就可以更灵活地管理任务。
|
||||
|
||||
牛牛也新增了理智作战任务的周计划设置,可按星期数(如星期三、星期二、星期五等)设置任务是否执行。这样你就可以结合上面提到的添加任务,<u>在理智作战任务前添加另一个理智作战任务,并将其设置为仅打当期剿灭、仅在星期一运行</u>,更多用法等你探索~
|
||||
|
||||
另外,在牛牛执行一键长草流程时,各个任务的勾选框会根据其运行状态以不同颜色进行区分,直观反馈任务被跳过、已完成、运行中或执行失败等状态。
|
||||
|
||||
注:由于牛牛现已支持 「理智作战」 周计划并可添加多个同类型任务,本次更新**移除了原有 「剿灭作战」 任务失败后自动尝试下一个已开放的备选逻辑**,如有需要请参照上方的示例添加对应任务。
|
||||
|
||||
#### PC 端初步支持
|
||||
|
||||
本次更新,牛牛已支持控制 PC 端明日方舟了~不过有以下限制:
|
||||
|
||||
* 由于 Windows 的限制,PC 端在被控制时**不可以处于最小化窗口状态**,否则游戏画面不会被渲染,也就无法被牛牛识别;
|
||||
* 由于 Win32 API 和某反作弊软件的限制,牛牛在控制 PC 端时**必须要直接控制鼠标(不能模拟点击)**,期间不建议你使用鼠标。
|
||||
|
||||
另外,由于维护人手有限,PC 端的适配可能长期处于不稳定状态,部分功能可能出现异常或暂时无法使用。
|
||||
|
||||
我们非常欢迎社区开发者协助适配并提交改进,共同完善对 PC 端的支持。
|
||||
|
||||
#### 其他方面
|
||||
|
||||
* 我们继续对界园肉鸽进行适配,包括 DLC 2 的更新支持;
|
||||
* 我们优化了自动编队的识别,现在支持对作业要求的精英化、等级和模组的识别,如果发现你的干员不满足要求将会有对应提示;
|
||||
* 相应的,干员识别功能也支持显示精英化和等级了。
|
||||
|
||||
----
|
||||
|
||||
#### Restructuring of *Farming* Configuration for Windows
|
||||
|
||||
In this update, we have restructured the *Farming* configuration for Windows, addressing several pain points.
|
||||
|
||||
MAA now supports adding multiple tasks of the same type and renaming them. You can add multiple tasks of the same type using the plus button at the bottom left of the *Farming* panel, adjust the execution order by dragging tasks, and rename or delete tasks by right-clicking the gear icon on the right side of each task. This allows for more flexible task management.
|
||||
|
||||
MAA also supports weekly schedule settings for *Combat* tasks, allowing you to specify on which days of the week (e.g., Monday, Thursday) a task should run. For example, you can add another *Combat* task before your existing one and set it to only run Current Annihilation on Mondays. More usage scenarios await your exploration!
|
||||
|
||||
Additionally, when MAA executes the *Farming* process, the checkboxes for each task will be color-coded to indicate their status: skipped, completed, running, or failed, providing intuitive feedback.
|
||||
|
||||
Note: Since MAA now supports weekly schedules for *Combat* tasks and allows adding multiple tasks of the same type, this update **removes the previous logic that automatically attempted the next available alternative stage after a "Current Annihilation" task failure**. If needed, please refer to the example above to add corresponding tasks.
|
||||
|
||||
#### Preliminary PC Client Support (**[CN ONLY]**)
|
||||
|
||||
In this update, MAA now supports controlling the PC client of Arknights.
|
||||
|
||||
However, due to limited maintenance resources, PC client adaptation may remain unstable for a long period, and some features may experience issues or be temporarily unavailable.
|
||||
|
||||
We warmly welcome community developers to assist with adaptation and submit improvements to collectively enhance PC client support.
|
||||
|
||||
#### Other Updates
|
||||
|
||||
* Continued adaptation for *Sui's Garden of Grotesqueries*, including support for DLC 2 updates (**[CN ONLY]**)
|
||||
* Optimized recognition in *Auto Squad*, which now supports identifying elite, level, and module requirements. If your operators do not meet the requirements, you will receive corresponding prompts.
|
||||
* The operator recognition feature now also supports displaying elite and level information.
|
||||
|
||||
----
|
||||
|
||||
以下是详细内容:
|
||||
|
||||
## v6.3.2
|
||||
## v5.26.0-beta.1
|
||||
|
||||
### 新增 | New
|
||||
|
||||
* 睡眠休眠前增加倒计时弹窗 @ABA2396
|
||||
* 生息演算支援道具名称改为全字匹配 @ABA2396
|
||||
|
||||
### 改进 | Improved
|
||||
|
||||
* 干员识别按照 稀有度->精英化->等级->潜能->Id 排序 @ABA2396
|
||||
* 优化识别工具中列表小于 5 时的显示效果 @ABA2396
|
||||
* optimize templates @Constrat
|
||||
* increase score for AddOperatorTradeAggressive EN @Constrat
|
||||
* 次生预案十里坡剑神 @ABA2396
|
||||
* 设置指引添加更新设置 @ABA2396
|
||||
* 设置指引添加性能设置 @ABA2396
|
||||
|
||||
### 修复 | Fix
|
||||
|
||||
* 4 星公招时间显示错误 @ABA2396
|
||||
* 刷理智自定义剿灭关卡在特定情况的绑定错误 @status102
|
||||
* 在禁用刷理智-自定义剿灭关卡后需要手动切换任务以刷新列表中显示的剿灭关卡, 尽管不影响实际运行 @status102
|
||||
* 会客室任务失败重试时尝试关闭赠送线索界面 @ABA2396
|
||||
* 肉鸽开局种子无法通过 Wpf 设置两位数难度 @status102
|
||||
* 小工具-公招识别 3~5 星选择时间无法修改 @status102
|
||||
* 小工具-干员识别 开始识别按钮启用状态绑定失效 @status102
|
||||
* 自动公招任务 3~5 星确认时间在修改后未能刷新 UI @status102
|
||||
* EN AveMujica terminal new template @Constrat
|
||||
* EN IS tentative fix increasing roi for encounter and more replace regex @Constrat
|
||||
* English text overflow on long strings in middle column @Constrat
|
||||
* 文档首页语言选择按钮的宽度定义方式 (#14199) @lucienshawls
|
||||
* 傀影肉鸽无法识别四结局 (#14193) @Saratoga-Official
|
||||
* GamePassSkip2 识别到错误的跳过 @Saratoga-Official
|
||||
* 萨米肉鸽不期而遇避战 @Saratoga-Official
|
||||
* Google Play Games Developer shutdown @Constrat
|
||||
* manual set resource version time @MistEO
|
||||
* prettier @Constrat
|
||||
|
||||
### 文档 | Docs
|
||||
|
||||
* 删除一些过时内容 (#15700) @JasonHuang79
|
||||
* 补充vsc插件繁中文档 @Rbqwow
|
||||
* 修复文档站 readme 盾换行 @Rbqwow
|
||||
* 调整文档站的标题和尾注文本显示 (#14213) @lucienshawls
|
||||
* 更新网页开发相关文档 (#14167) @Rbqwow @Manicsteiner
|
||||
* 完善任务流程协议文档 (#13232) @zzyyyl
|
||||
* 回调消息协议文档视觉更新 @SherkeyXD
|
||||
* 集成文档视觉更新 @SherkeyXD
|
||||
* 文档启用 b 站视频播放功能 @SherkeyXD
|
||||
* 文档添加字段容器功能 @SherkeyXD
|
||||
* 文档添加功能 @SherkeyXD
|
||||
* 更新文档编写指南 @SherkeyXD
|
||||
* 标题 MAA 统一采用缩写 @MistEO
|
||||
* 再次调整文档站标题( @MistEO
|
||||
* 调整文档站标题 @MistEO
|
||||
* Update JP(#14227) @wallsman
|
||||
* markdown pre-commit @zzyyyl
|
||||
* add extension's evaluating feature @neko-para
|
||||
* add telegram icon @SherkeyXD
|
||||
|
||||
### 其他 | Other
|
||||
|
||||
* 增加 id 格式验证 @ABA2396
|
||||
* 明确周计划和定时更新使用游戏时间而非现实时间 @ABA2396
|
||||
* 移除老主线导航逻辑 (#15644) @SherkeyXD
|
||||
* 繁中服「夢鄉」主題 (#15699) @momomochi987
|
||||
* Yostar servers SSS#9 and ShamareThumbnail (#15732) @Manicsteiner @Constrat
|
||||
|
||||
## v6.3.1
|
||||
|
||||
### 新增 | New
|
||||
|
||||
* OperNameAnalyzer 支持左对齐检测 (#15682) @ABA2396
|
||||
|
||||
### 改进 | Improved
|
||||
|
||||
* 配置迁移自动为启用备选且首个关卡为剿灭模式的刷理智任务自动添加额外的刷理智任务 @status102
|
||||
* 忽略干员属性要求 不再允许跳过精英化要求 (#15697) @status102 @Constrat @HX3N
|
||||
|
||||
### 修复 | Fix
|
||||
|
||||
* JP AveMujica event ocr @Manicsteiner
|
||||
* EN IS StageRefresh @Constrat
|
||||
* i'm kinda stupid @Constrat
|
||||
* update refresh node EN IS5 @Constrat
|
||||
* EN IS fix trader store templates AGAIN @Constrat
|
||||
* EN Yu OCR for Yutenji @Constrat
|
||||
* 自动编队选择技能时点击到技能描述/技能范围 @status102
|
||||
* 自动编队期间如有干员属性要求被忽略, 则禁用自动化投票 @status102
|
||||
|
||||
### 文档 | Docs
|
||||
|
||||
* 更新 api 链接 @ABA2396
|
||||
|
||||
### 其他 | Other
|
||||
|
||||
* UserAdditional 非 json 格式返回原始字符串 @status102
|
||||
* 使用屏幕宽高常量代替硬编码 @status102
|
||||
* 屏幕外的干员跳过技能就绪检测 @status102
|
||||
* 調整繁中服界園肉鴿 OCR (2/?) @momomochi987
|
||||
* color [INF] for smoke testing as well @Constrat
|
||||
* 调整单字干员正则 @ABA2396
|
||||
* 調整繁中服界園肉鴿 OCR (#15678) @momomochi987
|
||||
* 删除干员名开头/末尾的_<> @ABA2396
|
||||
* 添加响石、赤刃明霄陈基建技能加成 (#15674) @drway
|
||||
* 保全派驻自动战斗使用二值化结果识别干员名 @ABA2396
|
||||
* 删除无用的正则替换 @ABA2396
|
||||
* 自动战斗使用二值化结果识别干员名 @ABA2396
|
||||
* 仅在 VS Code 中添加辅助项目 (#15669) @status102
|
||||
* JP OperNameAnalyzer specialParams @Manicsteiner
|
||||
|
||||
## v6.3.0
|
||||
|
||||
### 新增 | New
|
||||
|
||||
* 支持 PC 端明日方舟 (#15407) @MistEO @ABA2396
|
||||
* SideStory「辞岁行」导航及地图数据更新 @SherkeyXD @status102
|
||||
* 界园肉鸽 DLC 2 分队更新、通宝数据更新、可选难度提高至 18、支持指定种子开局 (#15588) @SherkeyXD @status102 @HX3N @Manicsteiner
|
||||
* 繁中服界園肉鴿初步適配 (#15605) @momomochi987
|
||||
* 干员识别支持显示精英化、等级与潜能 @ABA2396
|
||||
* 自动编队识别精英化、等级及模组要求 (#15161) @status102 @Manicsteiner @Constrat @HX3N
|
||||
* 芯片本支持显示库存数量 @ABA2396
|
||||
* 新增注入弹窗不再提醒的勾选框,勾选后使用软件渲染 @ABA2396
|
||||
* WpfGui 清空缓存按钮 (#15582) @soundofautumn @Constrat @HX3N @momomochi987
|
||||
* 自定干员名称无效时的错误处理及本地化支持 (#15556) @yali-hzy @HX3N
|
||||
* 设置指引增加右键重命名/删除提示 @ABA2396
|
||||
* 新 Config 加载时移除旧 Config 中不存在的配置 @status102
|
||||
* 日志中额外记录 TaskChain 与 taskId ~~免得有人把 Fight 改成开始唤醒~~ @ABA2396
|
||||
* YostarEN/JP/KR Dreamland、JieGarden 和 AveMujica 主题支持 @Constrat @Manicsteiner @HX3N
|
||||
|
||||
### 改进 | Improved
|
||||
|
||||
* Wpf 一键长草任务配置重构,支持添加多个同类型任务、重命名和周计划设置 (#15385) @status102 @ABA2396 @momomochi987 @HX3N
|
||||
* 刷理智过期关卡逻辑/样式优化 @status102 @ABA2396
|
||||
* 关卡候选列表刷新及关卡选择下拉列表刷新 (#15562) @status102 @HX3N @Constrat @Manicsteiner @momomochi987
|
||||
* 优化自动战斗界面布局 (#15512) @yali-hzy
|
||||
* 优化任务设置按钮悬浮提示 @ABA2396
|
||||
* 优化设置右键菜单布局 @ABA2396
|
||||
* 优化干员识别、仓库识别显示 @ABA2396
|
||||
* 配置迁移检查优化与简化 @status102 @ABA2396
|
||||
* 开始唤醒任务未设置账号切换时,禁用手动切换按钮 @status102
|
||||
* 自动战斗掉线重连、自动肉鸽在战斗结束前延迟「停止」动作添加多任务共用提示 @ABA2396 @status102
|
||||
* 剿灭卡使用到上限时不报错停止 @ABA2396
|
||||
* 剿灭关卡通过 ends_with 判断 @ABA2396
|
||||
* 刷理智任务高级设置 UI 调整选项顺序和显示优化 @status102
|
||||
* 自动战斗自动编队检查`干员等级&精英化`及`技能等级`拆分 @status102
|
||||
* 自动战斗不支持技能重置说明中,干员名遵循干员名语言设置 @status102
|
||||
* 自动战斗作业列表使用相对路径代替绝对路径 @status102
|
||||
* TaskQueue 重命名与移除时显示任务序号 @status102
|
||||
* TaskQueue 任务开始&完成显示修改后的任务名 @status102
|
||||
* 追加自定干员允许不切换技能 @status102
|
||||
* 存在 crash.log 时,Wpf 尝试获取 dumps 文件 (#15432) @status102
|
||||
* 移除过时的参数兼容 @status102
|
||||
* 消除部分编译警告 (#15578) @yali-hzy
|
||||
* NumberOcrReplace 新增规则 (#14186) @Manicsteiner
|
||||
|
||||
### 修复 | Fix
|
||||
|
||||
* 配置迁移相关问题修复:迁移后切换回原配置、删除配置时未删除 .new、多配置用户删除 Default 配置时迁移异常、剩余理智启用状态和关卡选择迁移问题 @status102 @ABA2396
|
||||
* 刷理智任务相关修复:切换刷理智任务时读取错误关卡列表、运行时不允许添加关卡 @status102
|
||||
* 自动编队相关修复:识别技能等级匹配失败、干员技能描述过长时点击位置错误、禁用快速选中以修复外服干员技能描述过长的错误选中、干员等级跨精英化时判断出错、干员等级不足 i18n 未启用、干员组干员未解析精英化及等级属性、先兼容旧作业中不合理的技能选择 @status102
|
||||
* 公招加速券识别问题修复 @status102
|
||||
* LoadApiCache 路径拼接错误 @ABA2396
|
||||
* 主线导航及外服主线导航问题修复 @SherkeyXD @ABA2396
|
||||
* 在赠送线索时弹出上次线索交流结束的提示时无法返回 @ABA2396
|
||||
* 粘贴作业集代码后下方的链接未重置为作业站链接 @ABA2396
|
||||
* 修复移动已打开设置的任务后,当前的设置面板无法继续修改的问题 @ABA2396
|
||||
* 萨米肉鸽刷开局功能异常 @ABA2396
|
||||
* 肉鸽烧水分队切换界面后错误重置 @status102
|
||||
* 保证通宝优先级未定义时不会加载崩溃 fallback 到默认值 @SherkeyXD
|
||||
* SEH 错误终止运行 @status102
|
||||
* 启动 MAA 时若没有任何任务,则追加一套默认任务 @status102
|
||||
* 启动客户端绑定失效问题修复 @status102
|
||||
* 关卡列表显示不刷新 @status102
|
||||
* 选中完成后动作时添加新任务未能隐藏完成后动作设置 UI @status102
|
||||
* 刷理智使用源石 CheckBox 勾选后不生效 @status102
|
||||
* 退出 MAA 时重置变量不再刷新 UI @status102
|
||||
* 初始化 StartEnabled 属性为 true (#15596) @yali-hzy
|
||||
* 自动战斗切换活动类型未清空解析缓存 @status102
|
||||
* 修复任务出错日志可能晚于任务完成日志显示的问题 @ABA2396
|
||||
* 开始干员识别前重置潜能状态 @ABA2396
|
||||
* 修复生息演算商店无法正常购买皮肤的问题 (#15585) @drway
|
||||
* 手动输入关卡名时,不移除过期关卡 @status102
|
||||
* 过期关卡重置模式补充自动迁移 @status102
|
||||
* OR 关卡掉落界面关卡名识别问题 @ABA2396
|
||||
* EX 关符合时 1 被识别为 | @ABA2396
|
||||
* NumberOcrReplace 移除`|`和`/` (#15625) @status102
|
||||
* 移除单字干员 ocr 替换中的 +*?避免误判 @Saratoga-Official
|
||||
* 涤火杰西卡识别 @ABA2396
|
||||
* 日服酒神、見字祠识别 @Saratoga-Official
|
||||
* YostarKR Roguelike@ChooseOperConfirm @HX3N
|
||||
* YostarKR use ' ' in ocrReplace to preserve '\n' for InfrastTrainingTask @HX3N
|
||||
* EN Greyy Alter regex @Constrat
|
||||
* EN IS6 encounter @Constrat
|
||||
* EN IS TradeInvest templates text font change @Constrat
|
||||
* EN IS ShoppingConfirm text font change @Constrat
|
||||
* EN refresh node template @Constrat
|
||||
* JP AT minigame confirm (#15427) @Manicsteiner
|
||||
* JP JieGardenStrategyChange @Saratoga-Official
|
||||
* add MaaWin32ControlUnit to nightly build (#15447) @Manicsteiner
|
||||
|
||||
### 文档 | Docs
|
||||
|
||||
* 集成文档统一格式,同时显示 field-group 和示例代码 (#15409) @ABA2396 @Manicsteiner @Constrat @momomochi987
|
||||
* 繁中文件大更新 (#15480) @momomochi987
|
||||
* 修正开发文档中的格式错误及笔误 (#15516) @yali-hzy
|
||||
* 自动战斗作业文档干员技能值范围补上 0 @status102
|
||||
|
||||
### 其他 | Other
|
||||
|
||||
* 作业集 Parse 后不删除历史记录,避免错过作业抛出的错误 @ABA2396
|
||||
* 辞岁行地图 2026-02-10 Map 更新 @status102
|
||||
* 繁中服不上报企鹅物流 @ABA2396
|
||||
* devcontainer 适配 CMakePresets.json (#15606) @lucienshawls
|
||||
* 移除不再使用的 VirtualizingWrapPanel 与 NoAutomationDataGrid @ABA2396
|
||||
* 调整清理图片缓存样式,增加提示 @ABA2396
|
||||
* 补全缺少的翻译 @ABA2396
|
||||
* 优化 emoji @ABA2396
|
||||
* 自动战斗-自动编队干员不支持技能说明国际化 (#15609) @status102 @Constrat @HX3N @Manicsteiner
|
||||
* 自动战斗编队技能等级不足 i18n,CN 使用理智药及碎石文案 (#15435) @status102 @HX3N
|
||||
* 增加借助战 OF-1 在后续刷理智选择`当前/上次`导致禁用时的输出 (#15478) @status102 @Manicsteiner @Constrat @HX3N @ABA2396 @momomochi987
|
||||
* remove regex from `text` field in EN Sui IS @Constrat
|
||||
* KR AnnouncementNotFinishedConfirm、ReceptionOptionsRequireInfrast、CreditFightWhenOF-1Warning、MiniGame ConversationRoom and HoneyFruit 支持 @HX3N
|
||||
* EN minigame honeyfruit、IS6 tip 支持 @Constrat
|
||||
* JP MiniGame HoneyFruit 支持 @Manicsteiner
|
||||
* YostarJP ocr fix for roguelike @Manicsteiner
|
||||
* manual data for txwy @Constrat
|
||||
* optimize templates @Constrat
|
||||
* fix casing typo and related context (#15656) @ittuann @Daydreamer114
|
||||
* 统一显示效果 @ABA2396
|
||||
* 水月萨米肉鸽不期而遇避战 @Saratoga-Official
|
||||
* 重写完成后动作仅一次的 ui 字符串 (#14196) @Rbqwow
|
||||
* 贸易站没其他好用的人再用锏 @ABA2396
|
||||
* YostarJP Sarkaz roguelike StageEncounter (#14223) @Manicsteiner
|
||||
* YostarJP sami roguelike 720p (#14210) @Manicsteiner
|
||||
* YostarJP Mizuki StageEncounter (#14206) @Manicsteiner
|
||||
* devcontainer.json (#14169) @Rbqwow @lucienshawls
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
|
||||
project(MAA)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules")
|
||||
|
||||
option(BUILD_WPF_GUI "build MaaWpfGui" ${WIN32})
|
||||
option(BUILD_DEBUG_DEMO "build debug demo" OFF)
|
||||
option(BUILD_XCFRAMEWORK "build xcframework for macOS app" OFF)
|
||||
@@ -12,36 +17,35 @@ option(INSTALL_FLATTEN "do not use bin lib include directory" ON)
|
||||
option(WITH_EMULATOR_EXTRAS "build with emulator extras" ${WIN32})
|
||||
option(WITH_HASH_VERSION "generate version from git hash" OFF)
|
||||
|
||||
if(INSTALL_FLATTEN)
|
||||
set(RPATH_LIBRARY_INSTALL_DIR .)
|
||||
set(MaaCore_install_flatten_args RUNTIME DESTINATION . LIBRARY DESTINATION . PUBLIC_HEADER DESTINATION .)
|
||||
endif()
|
||||
include(${PROJECT_SOURCE_DIR}/MaaDeps/maadeps.cmake)
|
||||
|
||||
include(src/MaaUtils/MaaUtils.cmake)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules")
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/config.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/utils.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/version.cmake)
|
||||
|
||||
if(APPLE)
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/macos.cmake)
|
||||
endif()
|
||||
|
||||
if(INSTALL_FLATTEN)
|
||||
set(MaaCore_install_flatten_args RUNTIME DESTINATION . LIBRARY DESTINATION . PUBLIC_HEADER DESTINATION .)
|
||||
endif()
|
||||
|
||||
add_library(HeaderOnlyLibraries INTERFACE)
|
||||
target_include_directories(HeaderOnlyLibraries INTERFACE 3rdparty/include)
|
||||
|
||||
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs)
|
||||
find_package(Boost REQUIRED CONFIG COMPONENTS system)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(fastdeploy_ppocr REQUIRED)
|
||||
find_package(ONNXRuntime REQUIRED)
|
||||
|
||||
add_subdirectory(src/MaaCore)
|
||||
|
||||
if(BUILD_WPF_GUI)
|
||||
include_external_msproject(MaaWpfGui ${PROJECT_SOURCE_DIR}/src/MaaWpfGui/MaaWpfGui.csproj)
|
||||
|
||||
add_dependencies(MaaWpfGui MaaCore)
|
||||
if(DEFINED ENV{VSCODE_PID})
|
||||
add_custom_target(run-MaaWpfGui
|
||||
COMMAND "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/MAA.exe"
|
||||
DEPENDS MaaWpfGui
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$<CONFIG>"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(INSTALL_PYTHON)
|
||||
|
||||
@@ -1,348 +0,0 @@
|
||||
{
|
||||
"version": 10,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 23,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "windows-base",
|
||||
"hidden": true,
|
||||
"generator": "Visual Studio 18 2026",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"$comment": [
|
||||
"Base for Windows presets; Visual Studio is multi-config (Debug/Release/RelWithDebInfo in same build dir)",
|
||||
"see https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2018%202026.html"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"BUILD_WPF_GUI": "ON",
|
||||
"BUILD_DEBUG_DEMO": "ON",
|
||||
"INSTALL_RESOURCE": "OFF",
|
||||
"INSTALL_PYTHON": "OFF"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-base",
|
||||
"hidden": true,
|
||||
"generator": "Ninja Multi-Config",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"$comment": [
|
||||
"Base for Linux presets; Ninja is multi-config (Debug/Release/RelWithDebInfo in same build dir)",
|
||||
"see https://cmake.org/cmake/help/latest/generator/Ninja%20Multi-Config.html",
|
||||
"clangd uses compile_commands.json to provide code completion and navigation",
|
||||
"so CMAKE_EXPORT_COMPILE_COMMANDS is set to ON",
|
||||
"see https://clangd.llvm.org/installation.html"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-base",
|
||||
"hidden": true,
|
||||
"generator": "Ninja Multi-Config",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"$comment": [
|
||||
"Base for macOS presets; Ninja is multi-config (Debug/Release/RelWithDebInfo in same build dir)",
|
||||
"see https://cmake.org/cmake/help/latest/generator/Ninja%20Multi-Config.html",
|
||||
"clangd uses compile_commands.json to provide code completion and navigation",
|
||||
"so CMAKE_EXPORT_COMPILE_COMMANDS is set to ON",
|
||||
"see https://clangd.llvm.org/installation.html"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-x64",
|
||||
"inherits": "windows-base",
|
||||
"displayName": "Windows x64",
|
||||
"architecture": "x64",
|
||||
"cacheVariables": {
|
||||
"MAADEPS_TRIPLET": "maa-x64-windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-arm64",
|
||||
"inherits": "windows-base",
|
||||
"displayName": "Windows arm64",
|
||||
"architecture": "ARM64",
|
||||
"cacheVariables": {
|
||||
"MAADEPS_TRIPLET": "maa-arm64-windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x64",
|
||||
"inherits": "linux-base",
|
||||
"displayName": "Linux x64",
|
||||
"toolchainFile": "src/MaaUtils/MaaDeps/cmake/maa-x64-linux-toolchain.cmake",
|
||||
"cacheVariables": {
|
||||
"MAADEPS_TRIPLET": "maa-x64-linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-arm64",
|
||||
"inherits": "linux-base",
|
||||
"displayName": "Linux arm64",
|
||||
"toolchainFile": "src/MaaUtils/MaaDeps/cmake/maa-arm64-linux-toolchain.cmake",
|
||||
"cacheVariables": {
|
||||
"MAADEPS_TRIPLET": "maa-arm64-linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-arm64",
|
||||
"inherits": "macos-base",
|
||||
"displayName": "macOS arm64",
|
||||
"cacheVariables": {
|
||||
"CMAKE_OSX_ARCHITECTURES": "arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos-x64",
|
||||
"inherits": "macos-base",
|
||||
"displayName": "macOS x64",
|
||||
"cacheVariables": {
|
||||
"CMAKE_OSX_ARCHITECTURES": "x86_64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "publish-base",
|
||||
"$comment":[
|
||||
"All the name contains 'publish' are used for github actions",
|
||||
"see .github/workflows/ci.yml"
|
||||
],
|
||||
"hidden": true,
|
||||
"installDir": "install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"INSTALL_RESOURCE": "ON",
|
||||
"INSTALL_PYTHON": "ON",
|
||||
"BUILD_WPF_GUI": "OFF",
|
||||
"BUILD_DEBUG_DEMO": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-publish-x64",
|
||||
"inherits": ["publish-base", "windows-x64"],
|
||||
"$comment": [
|
||||
"github actions only support Visual Studio 17 2022",
|
||||
"see https://github.com/actions/runner-images/issues/13291"
|
||||
],
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"displayName": "Windows x64 Publish"
|
||||
},
|
||||
{
|
||||
"name": "windows-publish-arm64",
|
||||
"inherits": ["publish-base", "windows-arm64"],
|
||||
"$comment": [
|
||||
"github actions only support Visual Studio 17 2022",
|
||||
"see https://github.com/actions/runner-images/issues/13291"
|
||||
],
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"displayName": "Windows arm64 Publish"
|
||||
},
|
||||
{
|
||||
"name": "linux-publish-x64",
|
||||
"inherits": ["publish-base", "linux-x64"],
|
||||
"displayName": "Linux x64 Publish"
|
||||
},
|
||||
{
|
||||
"name": "linux-publish-arm64",
|
||||
"inherits": ["publish-base", "linux-arm64"],
|
||||
"displayName": "Linux arm64 Publish"
|
||||
},
|
||||
{
|
||||
"name": "macos-publish-x64",
|
||||
"inherits": ["publish-base", "macos-x64"],
|
||||
"displayName": "macOS x64 Publish"
|
||||
},
|
||||
{
|
||||
"name": "macos-publish-arm64",
|
||||
"inherits": ["publish-base", "macos-arm64"],
|
||||
"displayName": "macOS arm64 Publish"
|
||||
},
|
||||
{
|
||||
"name": "smoke-test",
|
||||
"$comment":[
|
||||
"this preset is used for smoke testing",
|
||||
"see .github/workflows/smoke-testing.yml"
|
||||
],
|
||||
"inherits": "macos-arm64",
|
||||
"displayName": "macOS arm64 Smoke Test",
|
||||
"installDir": "install",
|
||||
"cacheVariables": {
|
||||
"BUILD_SMOKE_TEST": "ON",
|
||||
"INSTALL_RESOURCE": "ON",
|
||||
"WITH_HASH_VERSION": "ON"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "windows-x64-Debug",
|
||||
"displayName": "Build Windows x64 Debug",
|
||||
"configurePreset": "windows-x64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64-Release",
|
||||
"displayName": "Build Windows x64 Release",
|
||||
"configurePreset": "windows-x64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64-RelWithDebInfo",
|
||||
"displayName": "Build Windows x64 RelWithDebInfo",
|
||||
"configurePreset": "windows-x64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "windows-arm64-Debug",
|
||||
"displayName": "Build Windows arm64 Debug",
|
||||
"configurePreset": "windows-arm64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-arm64-Release",
|
||||
"displayName": "Build Windows arm64 Release",
|
||||
"configurePreset": "windows-arm64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "windows-arm64-RelWithDebInfo",
|
||||
"displayName": "Build Windows arm64 RelWithDebInfo",
|
||||
"configurePreset": "windows-arm64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-Debug",
|
||||
"displayName": "Build Linux x64 Debug",
|
||||
"configurePreset": "linux-x64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-Release",
|
||||
"displayName": "Build Linux x64 Release",
|
||||
"configurePreset": "linux-x64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-RelWithDebInfo",
|
||||
"displayName": "Build Linux x64 RelWithDebInfo",
|
||||
"configurePreset": "linux-x64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "linux-arm64-Debug",
|
||||
"displayName": "Build Linux arm64 Debug",
|
||||
"configurePreset": "linux-arm64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-arm64-Release",
|
||||
"displayName": "Build Linux arm64 Release",
|
||||
"configurePreset": "linux-arm64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "linux-arm64-RelWithDebInfo",
|
||||
"displayName": "Build Linux arm64 RelWithDebInfo",
|
||||
"configurePreset": "linux-arm64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "macos-x64-Debug",
|
||||
"displayName": "Build macOS x64 Debug",
|
||||
"configurePreset": "macos-x64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-x64-Release",
|
||||
"displayName": "Build macOS x64 Release",
|
||||
"configurePreset": "macos-x64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "macos-x64-RelWithDebInfo",
|
||||
"displayName": "Build macOS x64 RelWithDebInfo",
|
||||
"configurePreset": "macos-x64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "macos-arm64-Debug",
|
||||
"displayName": "Build macOS arm64 Debug",
|
||||
"configurePreset": "macos-arm64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-arm64-Release",
|
||||
"displayName": "Build macOS arm64 Release",
|
||||
"configurePreset": "macos-arm64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "macos-arm64-RelWithDebInfo",
|
||||
"displayName": "Build macOS arm64 RelWithDebInfo",
|
||||
"configurePreset": "macos-arm64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "windows-publish-x64",
|
||||
"displayName": "Build Windows x64 Publish",
|
||||
"configurePreset": "windows-publish-x64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "windows-publish-arm64",
|
||||
"displayName": "Build Windows arm64 Publish",
|
||||
"configurePreset": "windows-publish-arm64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "linux-publish-x64",
|
||||
"displayName": "Build Linux x64 Publish",
|
||||
"configurePreset": "linux-publish-x64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "linux-publish-arm64",
|
||||
"displayName": "Build Linux arm64 Publish",
|
||||
"configurePreset": "linux-publish-arm64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "macos-publish-x64",
|
||||
"displayName": "Build macOS x64 Publish",
|
||||
"configurePreset": "macos-publish-x64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "macos-publish-arm64",
|
||||
"displayName": "Build macOS arm64 Publish",
|
||||
"configurePreset": "macos-publish-arm64",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "smoke-test",
|
||||
"displayName": "Build macOS arm64 Smoke Test",
|
||||
"configurePreset": "smoke-test",
|
||||
"configuration": "Debug"
|
||||
}
|
||||
]
|
||||
}
|
||||
29
README.md
29
README.md
@@ -21,9 +21,6 @@
|
||||
<img alt="stars" src="https://img.shields.io/github/stars/MaaAssistantArknights/MaaAssistantArknights?style=social">
|
||||
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/MaaAssistantArknights/MaaAssistantArknights/total?style=social">
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://deepwiki.com/MaaAssistantArknights/MaaAssistantArknights"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
@@ -46,7 +43,7 @@ MAA 的意思是 MAA Assistant Arknights
|
||||
|
||||
## 亮点功能
|
||||
|
||||
- 理智作战,掉落识别及上传 [企鹅物流](https://penguin-stats.cn/),[一图流](https://ark.yituliu.cn/)
|
||||
- 刷理智,掉落识别及上传 [企鹅物流](https://penguin-stats.cn/),[一图流](https://ark.yituliu.cn/)
|
||||
- 智能基建换班,自动计算干员效率,单设施内最优解;同时也支持 [自定义排班](https://docs.maa.plus/zh-cn/protocol/base-scheduling-schema.html)
|
||||
- 自动公招,可选使用加急许可,一次全部刷完!公招数据自动上传 [企鹅物流](https://penguin-stats.cn/result/stage/recruit/recruit),[一图流](https://ark.yituliu.cn/survey/maarecruitdata)
|
||||
- 支持手动识别公招界面,方便对高星公招做出选择 ~~(你的这个高资回费出的是推王呢还是推王呢)~~
|
||||
@@ -101,9 +98,11 @@ MAA 支持命令行界面(CLI)操作,支持 Linux,macOS 和 Windows,
|
||||
|
||||
### 主要关联项目
|
||||
|
||||
**目前项目组非常缺前端大佬,若您有相关经验,欢迎加入我们!**
|
||||
|
||||
- 全新框架:[MaaFramework](https://github.com/MaaXYZ/MaaFramework)
|
||||
- [作业站](https://prts.plus) 前端:[zoot-plus-frontend](https://github.com/ZOOT-Plus/zoot-plus-frontend)
|
||||
- [作业站](https://prts.plus) 后端:[ZootPlusBackend](https://github.com/ZOOT-Plus/ZootPlusBackend)
|
||||
- [作业站](https://prts.plus) 前端:[maa-copilot-frontend](https://github.com/MaaAssistantArknights/maa-copilot-frontend)
|
||||
- [作业站](https://prts.plus) 后端:[MaaBackendCenter](https://github.com/MaaAssistantArknights/MaaBackendCenter)
|
||||
- [官网](https://maa.plus):[前端](https://github.com/MaaAssistantArknights/maa-website)
|
||||
- 深度学习:[MaaAI](https://github.com/MaaAssistantArknights/MaaAI)
|
||||
|
||||
@@ -113,9 +112,15 @@ MAA 以中文(简体)为第一语言,翻译词条均以中文(简体)
|
||||
|
||||
### 参与开发
|
||||
|
||||
请参阅 [开发指南](https://docs.maa.plus/zh-cn/develop/development.html)。
|
||||
#### Windows
|
||||
|
||||
### API
|
||||
请参阅 [开始开发](https://docs.maa.plus/zh-cn/develop/development.html)。
|
||||
|
||||
#### Linux | macOS
|
||||
|
||||
请参阅 [Linux 编译教程](https://docs.maa.plus/zh-cn/develop/linux-tutorial.html)。
|
||||
|
||||
#### API
|
||||
|
||||
- [C 接口](include/AsstCaller.h):[集成示例](src/Cpp/main.cpp)
|
||||
- [Python 接口](src/Python/asst/asst.py):[集成示例](src/Python/sample.py)
|
||||
@@ -131,11 +136,15 @@ MAA 以中文(简体)为第一语言,翻译词条均以中文(简体)
|
||||
- [任务流程协议](https://docs.maa.plus/zh-cn/protocol/task-schema.html)
|
||||
- [自动抄作业协议](https://docs.maa.plus/zh-cn/protocol/copilot-schema.html)
|
||||
|
||||
### 外服适配
|
||||
#### 外服适配
|
||||
|
||||
请参阅 [外服适配教程](https://docs.maa.plus/zh-cn/develop/overseas-client-adaptation.html),对于国服已支持的功能,绝大部分的外服适配工作仅需要截图 + 简单的 JSON 修改即可。
|
||||
|
||||
### Issue bot
|
||||
#### 想参与开发,但不太会用 GitHub?
|
||||
|
||||
[GitHub Pull Request 流程简述](https://docs.maa.plus/zh-cn/develop/development.html#github-pull-request-流程简述)
|
||||
|
||||
#### Issue bot
|
||||
|
||||
请参阅 [Issue Bot 使用方法](https://docs.maa.plus/zh-cn/develop/issue-bot-usage.html)
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
## 受支持的版本 / Supported Versions
|
||||
|
||||
我们仅对 v6 的最新稳定版提供安全支持,如有安全问题,我们将会尽可能快地发布新的稳定版解决。
|
||||
我们仅对 v4 和 v5 两个大版本的最新稳定版提供安全支持,如有安全问题,我们将会尽可能快地发布新的稳定版解决。
|
||||
|
||||
内测版、公测版仅供测试,我们不会对其提供安全支持。
|
||||
|
||||
We only provide security support for the latest Stable Release versions of v6. If there are security issues, we will release a new stable version as soon as possible to solve them.
|
||||
We only provide security support for the latest Stable Release versions of v4 and v5. If there are security issues, we will release a new stable version as soon as possible to solve them.
|
||||
|
||||
The Nightly Release version and the Beta Release version are for testing only, and we will not provide security support for them.
|
||||
|
||||
|
||||
@@ -1,2 +1,83 @@
|
||||
set(debug_comp_defs "_DEBUG;ASST_DEBUG")
|
||||
add_compile_definitions("$<$<CONFIG:Debug>:${debug_comp_defs}>")
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_INSTALL_RPATH "@loader_path;@executable_path")
|
||||
set(CMAKE_BUILD_RPATH "@loader_path;@executable_path")
|
||||
elseif(UNIX)
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN")
|
||||
set(CMAKE_BUILD_RPATH "$ORIGIN")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options("/utf-8")
|
||||
add_compile_options("/MP")
|
||||
add_compile_options("/W4;/WX;/Gy;/permissive-;/sdl")
|
||||
add_compile_options("/wd4127") # conditional expression is constant
|
||||
add_compile_options("/wd4251") # export dll with templates
|
||||
|
||||
add_compile_options("/DWINVER=0x0A00")
|
||||
add_compile_options("/D_WIN32_WINNT=0x0A00")
|
||||
|
||||
# https://github.com/actions/runner-images/issues/10004 https://github.com/microsoft/STL/releases/tag/vs-2022-17.10
|
||||
add_compile_definitions("_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR")
|
||||
|
||||
set(release_link_options "/OPT:REF;/OPT:ICF")
|
||||
add_link_options("$<$<CONFIG:Release>:${release_link_options}>")
|
||||
SET(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO "RelWithDebInfo;Release;")
|
||||
SET(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL "MinSizeRel;Release;")
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
else()
|
||||
add_compile_options("-Wall;-Werror;-Wextra;-Wpedantic;-Wno-missing-field-initializers")
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13)
|
||||
add_compile_options("-Wno-restrict")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
function(copy_and_add_rpath_library LIBNAME)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=${LIBNAME}.so.1 -target ${CMAKE_CXX_COMPILER_TARGET} --sysroot=${CMAKE_SYSROOT}
|
||||
OUTPUT_VARIABLE LIB_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if("${LIB_PATH}" STREQUAL "${LIBNAME}.so.1")
|
||||
message(FATAL_ERROR "Could not locate ${LIBNAME}.so.1 using compiler")
|
||||
endif()
|
||||
|
||||
file(READ_SYMLINK "${LIB_PATH}" LINK_TARGET)
|
||||
if(NOT LINK_TARGET)
|
||||
set(LIB_PATH_REAL "${LIB_PATH}")
|
||||
elseif(NOT IS_ABSOLUTE "${LINK_TARGET}")
|
||||
get_filename_component(LIB_PATH_DIR "${LIB_PATH}" DIRECTORY)
|
||||
file(REAL_PATH "${LIB_PATH_DIR}/${LINK_TARGET}" LIB_PATH_REAL)
|
||||
else()
|
||||
set(LIB_PATH_REAL "${LINK_TARGET}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${LIB_PATH_REAL}")
|
||||
message(FATAL_ERROR "File not found: ${LIB_PATH_REAL}")
|
||||
endif()
|
||||
|
||||
message(STATUS "${LIBNAME}.so.1 path: ${LIB_PATH_REAL}")
|
||||
|
||||
install(FILES "${LIB_PATH_REAL}" DESTINATION . RENAME "${LIBNAME}.so.1" COMPONENT libcxx)
|
||||
|
||||
get_filename_component(LIB_PATH_DIR "${LIB_PATH_REAL}" DIRECTORY)
|
||||
list(APPEND CMAKE_BUILD_RPATH "${LIB_PATH_DIR}")
|
||||
set(CMAKE_BUILD_RPATH "${CMAKE_BUILD_RPATH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
copy_and_add_rpath_library(libc++)
|
||||
copy_and_add_rpath_library(libc++abi)
|
||||
copy_and_add_rpath_library(libunwind)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
@@ -1,81 +1,27 @@
|
||||
if (BUILD_XCFRAMEWORK)
|
||||
set(XCFRAMEWORK_DIR "${CMAKE_BINARY_DIR}/xcframework")
|
||||
file(MAKE_DIRECTORY ${XCFRAMEWORK_DIR})
|
||||
|
||||
# Macro to find a unique library file
|
||||
macro(find_unique_library lib_name glob_pattern output_var)
|
||||
file(GLOB _libs CONFIGURE_DEPENDS "${MAADEPS_DIR}/runtime/${MAADEPS_TRIPLET}/${glob_pattern}")
|
||||
if(_libs)
|
||||
list(LENGTH _libs _cnt)
|
||||
if(_cnt EQUAL 1)
|
||||
list(GET _libs 0 ${output_var})
|
||||
message(STATUS "Found ${lib_name}: ${${output_var}}")
|
||||
else()
|
||||
message(FATAL_ERROR "Ambiguous ${lib_name} dylibs: ${_libs}")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "${lib_name} library not found in ${MAADEPS_DIR}/runtime/${MAADEPS_TRIPLET}/")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
add_custom_command(OUTPUT ${XCFRAMEWORK_DIR}/MaaCore.xcframework
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "${XCFRAMEWORK_DIR}/MaaCore.xcframework"
|
||||
COMMAND xcodebuild -create-xcframework
|
||||
-library $<TARGET_FILE:MaaCore>
|
||||
-headers ${PROJECT_SOURCE_DIR}/include
|
||||
-output MaaCore.xcframework
|
||||
add_custom_command(OUTPUT MaaCore.xcframework
|
||||
COMMAND rm -rf MaaCore.xcframework
|
||||
COMMAND xcodebuild -create-xcframework -library libMaaCore.dylib -headers ${PROJECT_SOURCE_DIR}/include -output MaaCore.xcframework
|
||||
DEPENDS MaaCore
|
||||
WORKING_DIRECTORY ${XCFRAMEWORK_DIR}
|
||||
COMMENT "Generating MaaCore.xcframework"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${XCFRAMEWORK_DIR}/MaaUtils.xcframework
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "${XCFRAMEWORK_DIR}/MaaUtils.xcframework"
|
||||
COMMAND xcodebuild -create-xcframework
|
||||
-library $<TARGET_FILE:MaaUtils>
|
||||
-output MaaUtils.xcframework
|
||||
DEPENDS MaaUtils
|
||||
WORKING_DIRECTORY ${XCFRAMEWORK_DIR}
|
||||
COMMENT "Generating MaaUtils.xcframework"
|
||||
)
|
||||
|
||||
find_unique_library("OpenCV" "libopencv_world*.dylib" OPENCV_LIB)
|
||||
add_custom_command(OUTPUT ${XCFRAMEWORK_DIR}/OpenCV.xcframework
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "${XCFRAMEWORK_DIR}/OpenCV.xcframework"
|
||||
COMMAND xcodebuild -create-xcframework
|
||||
-library "${OPENCV_LIB}"
|
||||
-output OpenCV.xcframework
|
||||
WORKING_DIRECTORY ${XCFRAMEWORK_DIR}
|
||||
COMMENT "Generating OpenCV.xcframework"
|
||||
add_custom_command(OUTPUT OpenCV.xcframework
|
||||
COMMAND rm -rf OpenCV.xcframework
|
||||
COMMAND xcodebuild -create-xcframework -library "${PROJECT_SOURCE_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/libopencv_world4.408.dylib" -output OpenCV.xcframework
|
||||
)
|
||||
|
||||
find_unique_library("ONNXRuntime" "libonnxruntime*.dylib" ONNXRUNTIME_LIB)
|
||||
add_custom_command(OUTPUT ${XCFRAMEWORK_DIR}/ONNXRuntime.xcframework
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "${XCFRAMEWORK_DIR}/ONNXRuntime.xcframework"
|
||||
COMMAND xcodebuild -create-xcframework
|
||||
-library "${ONNXRUNTIME_LIB}"
|
||||
-output ONNXRuntime.xcframework
|
||||
WORKING_DIRECTORY ${XCFRAMEWORK_DIR}
|
||||
COMMENT "Generating ONNXRuntime.xcframework"
|
||||
add_custom_command(OUTPUT ONNXRuntime.xcframework
|
||||
COMMAND rm -rf ONNXRuntime.xcframework
|
||||
COMMAND xcodebuild -create-xcframework -library "${PROJECT_SOURCE_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/libonnxruntime.1.18.0.dylib" -output ONNXRuntime.xcframework
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${XCFRAMEWORK_DIR}/fastdeploy_ppocr.xcframework
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "${XCFRAMEWORK_DIR}/fastdeploy_ppocr.xcframework"
|
||||
COMMAND xcodebuild -create-xcframework
|
||||
-library "${MAADEPS_DIR}/runtime/${MAADEPS_TRIPLET}/libfastdeploy_ppocr.dylib"
|
||||
-output fastdeploy_ppocr.xcframework
|
||||
WORKING_DIRECTORY ${XCFRAMEWORK_DIR}
|
||||
COMMENT "Generating fastdeploy_ppocr.xcframework"
|
||||
add_custom_command(OUTPUT fastdeploy_ppocr.xcframework
|
||||
COMMAND rm -rf fastdeploy_ppocr.xcframework
|
||||
COMMAND xcodebuild -create-xcframework -library "${PROJECT_SOURCE_DIR}/MaaDeps/runtime/${MAADEPS_TRIPLET}/libfastdeploy_ppocr.dylib" -output fastdeploy_ppocr.xcframework
|
||||
)
|
||||
|
||||
add_custom_target(MaaXCFramework ALL
|
||||
DEPENDS
|
||||
MaaCore
|
||||
${XCFRAMEWORK_DIR}/MaaCore.xcframework
|
||||
MaaUtils
|
||||
${XCFRAMEWORK_DIR}/MaaUtils.xcframework
|
||||
${XCFRAMEWORK_DIR}/OpenCV.xcframework
|
||||
${XCFRAMEWORK_DIR}/ONNXRuntime.xcframework
|
||||
${XCFRAMEWORK_DIR}/fastdeploy_ppocr.xcframework
|
||||
DEPENDS MaaCore MaaCore.xcframework OpenCV.xcframework ONNXRuntime.xcframework fastdeploy_ppocr.xcframework
|
||||
)
|
||||
endif (BUILD_XCFRAMEWORK)
|
||||
|
||||
|
||||
41
cmake/modules/FindONNXRuntime.cmake
Normal file
41
cmake/modules/FindONNXRuntime.cmake
Normal file
@@ -0,0 +1,41 @@
|
||||
find_path(ONNXRuntime_INCLUDE_DIR NAMES onnxruntime/onnxruntime_c_api.h)
|
||||
|
||||
find_library(ONNXRuntime_LIBRARY_IMP NAMES onnxruntime)
|
||||
|
||||
if (WIN32)
|
||||
get_filename_component(ONNXRuntime_PATH_LIB ${ONNXRuntime_LIBRARY_IMP} DIRECTORY)
|
||||
find_file(ONNXRuntime_LIBRARY NAMES onnxruntime_maa.dll PATHS "${ONNXRuntime_PATH_LIB}/../bin")
|
||||
|
||||
find_file(ONNXRuntime_LIBRARY_IMP_DEBUG NAMES onnxruntime.lib PATHS "${ONNXRuntime_PATH_LIB}/../debug/lib")
|
||||
find_file(ONNXRuntime_LIBRARY_DEBUG NAMES onnxruntime_maa.dll PATHS "${ONNXRuntime_PATH_LIB}/../debug/bin")
|
||||
else ()
|
||||
set(ONNXRuntime_LIBRARY ${ONNXRuntime_LIBRARY_IMP})
|
||||
endif (WIN32)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
ONNXRuntime
|
||||
REQUIRED_VARS ONNXRuntime_LIBRARY_IMP ONNXRuntime_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(ONNXRuntime_FOUND)
|
||||
set(ONNXRuntime_INCLUDE_DIRS ${ONNXRuntime_INCLUDE_DIR})
|
||||
if(NOT TARGET ONNXRuntime::ONNXRuntime)
|
||||
add_library(ONNXRuntime::ONNXRuntime SHARED IMPORTED)
|
||||
set_property(TARGET ONNXRuntime::ONNXRuntime APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
if (WIN32)
|
||||
set_property(TARGET ONNXRuntime::ONNXRuntime APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(ONNXRuntime::ONNXRuntime PROPERTIES
|
||||
IMPORTED_IMPLIB_RELEASE "${ONNXRuntime_LIBRARY_IMP}"
|
||||
)
|
||||
set_target_properties(ONNXRuntime::ONNXRuntime PROPERTIES
|
||||
IMPORTED_IMPLIB_DEBUG "${ONNXRuntime_LIBRARY_IMP_DEBUG}"
|
||||
IMPORTED_LOCATION_DEBUG "${ONNXRuntime_LIBRARY_DEBUG}"
|
||||
)
|
||||
endif (WIN32)
|
||||
set_target_properties(ONNXRuntime::ONNXRuntime PROPERTIES
|
||||
IMPORTED_LOCATION_RELEASE "${ONNXRuntime_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${ONNXRuntime_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,3 +1,50 @@
|
||||
function(download_and_decompress url filename sha256_checksum decompress_dir)
|
||||
if(EXISTS ${filename})
|
||||
file(SHA256 ${filename} CHECKSUM_VARIABLE)
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${filename} OR NOT CHECKSUM_VARIABLE STREQUAL sha256_checksum)
|
||||
message("Downloading file from ${url} to ${filename} ...")
|
||||
file(
|
||||
DOWNLOAD ${url} "${filename}.tmp"
|
||||
SHOW_PROGRESS
|
||||
EXPECTED_HASH SHA256=${sha256_checksum})
|
||||
file(RENAME "${filename}.tmp" ${filename})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${decompress_dir})
|
||||
file(MAKE_DIRECTORY ${decompress_dir})
|
||||
endif()
|
||||
|
||||
message("Decompress file ${filename} ...")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xf ${filename} WORKING_DIRECTORY ${decompress_dir})
|
||||
endfunction()
|
||||
|
||||
function(get_osx_architecture)
|
||||
if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
|
||||
set(CURRENT_OSX_ARCH
|
||||
"arm64"
|
||||
PARENT_SCOPE)
|
||||
elseif(CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64")
|
||||
set(CURRENT_OSX_ARCH
|
||||
"x86_64"
|
||||
PARENT_SCOPE)
|
||||
else()
|
||||
set(CURRENT_OSX_ARCH
|
||||
${CMAKE_HOST_SYSTEM_PROCESSOR}
|
||||
PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 13.3) # for to_chars
|
||||
get_osx_architecture()
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT DEFINED MAADEPS_TRIPLET)
|
||||
detect_maadeps_triplet(MAADEPS_TRIPLET)
|
||||
endif()
|
||||
|
||||
# 创建资源目录链接的函数
|
||||
function(create_resource_link TARGET_NAME OUTPUT_DIR)
|
||||
if(WIN32)
|
||||
@@ -12,7 +59,7 @@ function(create_resource_link TARGET_NAME OUTPUT_DIR)
|
||||
COMMENT "Creating junction for resource directory for ${TARGET_NAME}"
|
||||
)
|
||||
else()
|
||||
# UNIX/Linux/macOS 使用符号链接
|
||||
# Unix/Linux/macOS 使用符号链接
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
@@ -23,4 +70,4 @@ function(create_resource_link TARGET_NAME OUTPUT_DIR)
|
||||
COMMENT "Creating symlink for resource directory for ${TARGET_NAME}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
endfunction()
|
||||
27
cmake/version.cmake
Normal file
27
cmake/version.cmake
Normal file
@@ -0,0 +1,27 @@
|
||||
# define MAA_HASH_VERSION from git
|
||||
set(MAA_HASH_VERSION
|
||||
"DEBUG_VERSION"
|
||||
CACHE STRING "maa version")
|
||||
|
||||
if(WITH_HASH_VERSION AND MAA_HASH_VERSION STREQUAL "DEBUG_VERSION")
|
||||
find_package(Git)
|
||||
|
||||
if(GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_VARIABLE output
|
||||
ERROR_VARIABLE err
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if(result EQUAL 0)
|
||||
set(MAA_HASH_VERSION "${output}")
|
||||
else()
|
||||
message(WARNING "git rev-parse returning ${result}, output:\n${err}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "MAA_HASH_VERSION=${MAA_HASH_VERSION}")
|
||||
add_compile_definitions(MAA_VERSION="${MAA_HASH_VERSION}")
|
||||
@@ -1 +1,2 @@
|
||||
**/pnpm-lock.yaml
|
||||
**/*.md
|
||||
|
||||
@@ -11,6 +11,12 @@ module.exports = {
|
||||
arrowParens: 'always',
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
options: {
|
||||
semi: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.*css'],
|
||||
options: {
|
||||
@@ -30,11 +36,5 @@ module.exports = {
|
||||
tabWidth: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.md'],
|
||||
options: {
|
||||
embeddedLanguageFormatting: 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,21 +1,11 @@
|
||||
import { defineClientConfig } from 'vuepress/client'
|
||||
import { defineClientConfig } from 'vuepress/client';
|
||||
|
||||
import { getAsciiArt } from './plugins/asciiArt'
|
||||
import ImageGrid from './components/ImageGrid.vue';
|
||||
|
||||
import AsciiArt from './components/AsciiArt.vue'
|
||||
import ImageGrid from './components/ImageGrid.vue'
|
||||
import Redirect from './components/Redirect.vue'
|
||||
|
||||
import './styles/index.scss'
|
||||
import './styles/index.scss';
|
||||
|
||||
export default defineClientConfig({
|
||||
enhance: ({ app }) => {
|
||||
app.component('AsciiArt', AsciiArt)
|
||||
app.component('ImageGrid', ImageGrid)
|
||||
app.component('Redirect', Redirect)
|
||||
|
||||
// 输出一个随机的字符画
|
||||
const asciiArtData = getAsciiArt(undefined, 'auto', 'console')
|
||||
console.log('%c' + asciiArtData.text, 'white-space: pre;')
|
||||
app.component('ImageGrid', ImageGrid);
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
<template>
|
||||
<div ref="asciiArtWrapperElement" class="ascii-art-wrapper">
|
||||
<pre ref="asciiArtContentElement" class="ascii-art-content">{{ asciiArtText }}</pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { getAsciiArt, ThemeType, AsciiArtScope } from '../plugins/asciiArt'
|
||||
|
||||
// -------- Props --------
|
||||
interface AsciiArtProps {
|
||||
name?: string
|
||||
theme?: ThemeType
|
||||
scope?: AsciiArtScope
|
||||
}
|
||||
const props = defineProps<AsciiArtProps>()
|
||||
|
||||
// -------- Refs --------
|
||||
const asciiArtWrapperElement = ref<HTMLElement>()
|
||||
const asciiArtContentElement = ref<HTMLElement>()
|
||||
|
||||
// -------- Data --------
|
||||
let asciiArtNameInUse = props.name
|
||||
const asciiArtText = ref('')
|
||||
|
||||
let layoutObserver: ResizeObserver
|
||||
let themeObserver: MutationObserver
|
||||
|
||||
let isScaleUpLocked = false
|
||||
let lastScaleRatio = 1
|
||||
|
||||
function refreshAsciiArt() {
|
||||
const asciiArtData = getAsciiArt(asciiArtNameInUse, props.theme, props.scope)
|
||||
asciiArtNameInUse = asciiArtData.name
|
||||
asciiArtText.value = asciiArtData.text
|
||||
}
|
||||
|
||||
function scaleAsciiArt() {
|
||||
if (!asciiArtWrapperElement.value || !asciiArtContentElement.value) return
|
||||
|
||||
// 原始高度和宽度(无视scale)
|
||||
const contentWidth = asciiArtContentElement.value.scrollWidth
|
||||
const contentHeight = asciiArtContentElement.value.scrollHeight
|
||||
if (contentWidth === 0 || contentHeight === 0) return
|
||||
|
||||
const targetWidth = asciiArtWrapperElement.value.clientWidth
|
||||
const targetHeight = window.innerHeight
|
||||
|
||||
const scaleRatio = Math.min(targetWidth / contentWidth, targetHeight / contentHeight)
|
||||
// 锁定状态不允许放大
|
||||
if (scaleRatio > lastScaleRatio && isScaleUpLocked) return
|
||||
|
||||
lastScaleRatio = scaleRatio
|
||||
isScaleUpLocked = true
|
||||
|
||||
asciiArtContentElement.value.style.transform = `scale(${scaleRatio})`
|
||||
asciiArtWrapperElement.value.style.height = `${contentHeight * scaleRatio}px`
|
||||
}
|
||||
|
||||
function forceScaleAsciiArt() {
|
||||
isScaleUpLocked = false
|
||||
scaleAsciiArt()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!asciiArtWrapperElement.value || !asciiArtContentElement.value) return
|
||||
|
||||
layoutObserver = new ResizeObserver(scaleAsciiArt)
|
||||
layoutObserver.observe(asciiArtContentElement.value)
|
||||
layoutObserver.observe(asciiArtWrapperElement.value)
|
||||
|
||||
themeObserver = new MutationObserver(refreshAsciiArt)
|
||||
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] })
|
||||
|
||||
window.addEventListener('resize', forceScaleAsciiArt)
|
||||
|
||||
refreshAsciiArt()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (layoutObserver) {
|
||||
layoutObserver.disconnect()
|
||||
}
|
||||
if (themeObserver) {
|
||||
themeObserver.disconnect()
|
||||
}
|
||||
window.removeEventListener('resize', forceScaleAsciiArt)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ascii-art-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.ascii-art-content {
|
||||
display: block;
|
||||
white-space: pre;
|
||||
margin: 0 auto;
|
||||
transform-origin: top;
|
||||
line-height: 1;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +0,0 @@
|
||||
<template />
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vuepress/client'
|
||||
|
||||
interface Props {
|
||||
to?: string
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
function resolvePath(to: string) {
|
||||
const target = new URL(to, 'http://example.com' + route.path) // 使用一个虚拟的基础 URL
|
||||
return target.pathname
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.to) return
|
||||
const targetPath = resolvePath(props.to)
|
||||
router.replace(targetPath)
|
||||
})
|
||||
</script>
|
||||
@@ -1,13 +1,11 @@
|
||||
import { viteBundler } from '@vuepress/bundler-vite'
|
||||
import { defineUserConfig } from 'vuepress'
|
||||
import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics'
|
||||
import { plumeTheme } from 'vuepress-theme-plume'
|
||||
import { viteBundler } from '@vuepress/bundler-vite';
|
||||
import { defineUserConfig } from 'vuepress';
|
||||
import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics';
|
||||
import { plumeTheme } from 'vuepress-theme-plume';
|
||||
|
||||
import { genSiteLocales } from './navigation/genLocales'
|
||||
import DocSearchConfig from './plugins/search';
|
||||
|
||||
import DocSearchConfig from './plugins/search'
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
export default defineUserConfig({
|
||||
base: '/',
|
||||
@@ -17,7 +15,33 @@ export default defineUserConfig({
|
||||
host: '0.0.0.0',
|
||||
port: 3001,
|
||||
|
||||
locales: genSiteLocales(),
|
||||
locales: {
|
||||
'/zh-cn/': {
|
||||
lang: 'zh-CN',
|
||||
title: 'MAA 文档站',
|
||||
description: '文档',
|
||||
},
|
||||
'/zh-tw/': {
|
||||
lang: 'zh-TW',
|
||||
title: 'MAA 文件站',
|
||||
description: '文件',
|
||||
},
|
||||
'/en-us/': {
|
||||
lang: 'en-US',
|
||||
title: 'MAA Documentation Site',
|
||||
description: 'Documentation',
|
||||
},
|
||||
'/ja-jp/': {
|
||||
lang: 'ja-JP',
|
||||
title: 'MAA ドキュメントサイト',
|
||||
description: 'ドキュメント',
|
||||
},
|
||||
'/ko-kr/': {
|
||||
lang: 'ko-KR',
|
||||
title: 'MAA 문서 사이트',
|
||||
description: '문서',
|
||||
},
|
||||
},
|
||||
|
||||
head: [
|
||||
['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }],
|
||||
@@ -64,16 +88,17 @@ export default defineUserConfig({
|
||||
contributors: false,
|
||||
changelog: false,
|
||||
|
||||
blog: false,
|
||||
|
||||
cache: 'filesystem',
|
||||
|
||||
search: DocSearchConfig,
|
||||
|
||||
codeHighlighter: {
|
||||
themes: { light: 'snazzy-light', dark: 'night-owl' },
|
||||
themes: { light: 'one-light', dark: 'one-dark-pro' },
|
||||
},
|
||||
|
||||
markdown: {
|
||||
annotation: true,
|
||||
image: {
|
||||
lazyload: true,
|
||||
mark: true,
|
||||
@@ -107,4 +132,4 @@ export default defineUserConfig({
|
||||
id: 'G-FJQDKG394Z',
|
||||
}),
|
||||
],
|
||||
})
|
||||
});
|
||||
|
||||
5
docs/.vuepress/env.d.ts
vendored
Normal file
5
docs/.vuepress/env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue';
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
19
docs/.vuepress/navbar/en-us.ts
Normal file
19
docs/.vuepress/navbar/en-us.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineNavbarConfig } from 'vuepress-theme-plume';
|
||||
|
||||
export const enusNavbar = defineNavbarConfig([
|
||||
{
|
||||
text: 'User Manual',
|
||||
icon: 'mdi:user',
|
||||
link: '/en-us/manual/newbie.html',
|
||||
},
|
||||
{
|
||||
text: 'Development Docs',
|
||||
icon: 'ph:code-bold',
|
||||
link: '/en-us/develop/development.html',
|
||||
},
|
||||
{
|
||||
text: 'Protocol Docs',
|
||||
icon: 'basil:document-solid',
|
||||
link: '/en-us/protocol/integration.html',
|
||||
},
|
||||
]);
|
||||
5
docs/.vuepress/navbar/index.ts
Normal file
5
docs/.vuepress/navbar/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './zh-cn';
|
||||
export * from './zh-tw';
|
||||
export * from './en-us';
|
||||
export * from './ja-jp';
|
||||
export * from './ko-kr';
|
||||
19
docs/.vuepress/navbar/ja-jp.ts
Normal file
19
docs/.vuepress/navbar/ja-jp.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineNavbarConfig } from 'vuepress-theme-plume';
|
||||
|
||||
export const jajpNavbar = defineNavbarConfig([
|
||||
{
|
||||
text: '使用説明',
|
||||
icon: 'mdi:user',
|
||||
link: '/ja-jp/manual/newbie.html',
|
||||
},
|
||||
{
|
||||
text: '開発関連',
|
||||
icon: 'ph:code-bold',
|
||||
link: '/ja-jp/develop/development.html',
|
||||
},
|
||||
{
|
||||
text: 'プロトコルドキュメント',
|
||||
icon: 'basil:document-solid',
|
||||
link: '/ja-jp/protocol/integration.html',
|
||||
},
|
||||
]);
|
||||
19
docs/.vuepress/navbar/ko-kr.ts
Normal file
19
docs/.vuepress/navbar/ko-kr.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineNavbarConfig } from 'vuepress-theme-plume';
|
||||
|
||||
export const kokrNavbar = defineNavbarConfig([
|
||||
{
|
||||
text: '사용자 설명서',
|
||||
icon: 'mdi:user',
|
||||
link: '/ko-kr/manual/newbie.html',
|
||||
},
|
||||
{
|
||||
text: '개발 문서',
|
||||
icon: 'ph:code-bold',
|
||||
link: '/ko-kr/develop/development.html',
|
||||
},
|
||||
{
|
||||
text: '프로토콜 문서',
|
||||
icon: 'basil:document-solid',
|
||||
link: '/ko-kr/protocol/integration.html',
|
||||
},
|
||||
]);
|
||||
19
docs/.vuepress/navbar/zh-cn.ts
Normal file
19
docs/.vuepress/navbar/zh-cn.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineNavbarConfig } from 'vuepress-theme-plume';
|
||||
|
||||
export const zhcnNavbar = defineNavbarConfig([
|
||||
{
|
||||
text: '用户手册',
|
||||
icon: 'mdi:user',
|
||||
link: '/zh-cn/manual/newbie.html',
|
||||
},
|
||||
{
|
||||
text: '开发文档',
|
||||
icon: 'ph:code-bold',
|
||||
link: '/zh-cn/develop/development.html',
|
||||
},
|
||||
{
|
||||
text: '协议文档',
|
||||
icon: 'basil:document-solid',
|
||||
link: '/zh-cn/protocol/integration.html',
|
||||
},
|
||||
]);
|
||||
19
docs/.vuepress/navbar/zh-tw.ts
Normal file
19
docs/.vuepress/navbar/zh-tw.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineNavbarConfig } from 'vuepress-theme-plume';
|
||||
|
||||
export const zhtwNavbar = defineNavbarConfig([
|
||||
{
|
||||
text: '用戶說明書',
|
||||
icon: 'mdi:user',
|
||||
link: '/zh-tw/manual/newbie.html',
|
||||
},
|
||||
{
|
||||
text: '開發文件',
|
||||
icon: 'ph:code-bold',
|
||||
link: '/zh-tw/develop/development.html',
|
||||
},
|
||||
{
|
||||
text: '協議文件',
|
||||
icon: 'basil:document-solid',
|
||||
link: '/zh-tw/protocol/integration.html',
|
||||
},
|
||||
]);
|
||||
@@ -1,29 +0,0 @@
|
||||
import { SiteLocaleConfig, LocaleConfig } from 'vuepress'
|
||||
import { ThemeLocaleData } from 'vuepress-theme-plume'
|
||||
|
||||
import { locales } from './i18n'
|
||||
import { genNavigationComponents } from './genNavigationComponents'
|
||||
|
||||
export function genSiteLocales(): SiteLocaleConfig {
|
||||
const siteLocales: SiteLocaleConfig = {}
|
||||
for (const locale of locales) {
|
||||
siteLocales[`/${locale.name}/`] = {
|
||||
lang: locale.htmlLang,
|
||||
title: locale.siteTitle,
|
||||
description: locale.siteDescription,
|
||||
}
|
||||
}
|
||||
return siteLocales
|
||||
}
|
||||
|
||||
export function genThemeLocales(): LocaleConfig<ThemeLocaleData> {
|
||||
const themeLocales: LocaleConfig<ThemeLocaleData> = {}
|
||||
for (const locale of locales) {
|
||||
const navigationComponents = genNavigationComponents(locale)
|
||||
themeLocales[`/${locale.name}/`] = {
|
||||
navbar: navigationComponents.navbar,
|
||||
collections: navigationComponents.collections,
|
||||
}
|
||||
}
|
||||
return themeLocales
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { default as matter } from 'gray-matter'
|
||||
import { ThemeCollectionItem, ThemeNavItem, ThemeSidebarItem } from 'vuepress-theme-plume'
|
||||
|
||||
import { Locale } from './i18n'
|
||||
|
||||
interface MetaData {
|
||||
baseName: string
|
||||
order: number
|
||||
title: string
|
||||
icon: string
|
||||
index: boolean
|
||||
}
|
||||
|
||||
interface NavigationComponents {
|
||||
navbar: ThemeNavItem[]
|
||||
collections: ThemeCollectionItem[]
|
||||
}
|
||||
|
||||
type SidebarItem = ThemeSidebarItem | string
|
||||
|
||||
function getMetaData(dir: string, entry: fs.Dirent): MetaData | null {
|
||||
const currentPath = path.join(dir, entry.name)
|
||||
if (!fs.existsSync(currentPath)) {
|
||||
return null
|
||||
}
|
||||
|
||||
let mdFilePath = ''
|
||||
if (entry.isDirectory()) {
|
||||
mdFilePath = path.join(currentPath, 'README.md')
|
||||
} else if (entry.isFile() && entry.name.endsWith('.md') && entry.name.toLowerCase() !== 'readme.md') {
|
||||
mdFilePath = currentPath
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!fs.existsSync(mdFilePath)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const fileContent = fs.readFileSync(mdFilePath, 'utf-8')
|
||||
const meta = matter(fileContent).data ?? {}
|
||||
|
||||
// 文件名,不含扩展名
|
||||
const baseName = path.parse(entry.name).name
|
||||
// 获取顺序,目录的order在meta.dir.order里,文件的order在meta.order里,默认值为一个大数
|
||||
const order = Number((entry.isDirectory() ? meta?.dir?.order : meta?.order) ?? Number.MAX_SAFE_INTEGER)
|
||||
// 获取标题,先从matter里找title,再用正则获取一级标题,最后fallback到文件名(不含扩展名)
|
||||
const title = String(meta?.title ?? RegExp('# (.+)').exec(fileContent)?.[1] ?? baseName)
|
||||
// 获取图标
|
||||
const icon = String(meta?.icon ?? '')
|
||||
// 是否添加到索引,文件永远为true,目录则看meta.index,默认true
|
||||
const index = entry.isDirectory() ? (Boolean(meta?.index) ?? true) : true
|
||||
|
||||
return {
|
||||
baseName: baseName,
|
||||
order: order,
|
||||
title: title,
|
||||
icon: icon,
|
||||
index: index,
|
||||
}
|
||||
}
|
||||
|
||||
function getSidebarItems(dir: string): SidebarItem[] {
|
||||
interface WrappedSidebarItem {
|
||||
sidebarItem: SidebarItem
|
||||
order: number
|
||||
}
|
||||
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true }).filter((e) => !e.name.startsWith('.'))
|
||||
|
||||
const sidebarItemsWithOrder: WrappedSidebarItem[] = []
|
||||
for (const entry of entries) {
|
||||
let sidebarItem: SidebarItem
|
||||
|
||||
const metaData = getMetaData(dir, entry)
|
||||
if (!metaData) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
const children = getSidebarItems(path.join(dir, entry.name))
|
||||
// 可折叠的子目录
|
||||
sidebarItem = {
|
||||
text: metaData.title,
|
||||
// 只有当目录设置了index: true时,才生成链接,否则点击时不跳转、只切换折叠状态
|
||||
link: metaData.index ? `${metaData.baseName}/` : undefined,
|
||||
icon: metaData.icon,
|
||||
// 目前没有文档使用了badge这个特性,故不处理
|
||||
// badge: undefined,
|
||||
collapsed: true,
|
||||
// 前面不能加斜杠,必须用相对路径
|
||||
prefix: `${metaData.baseName}/`,
|
||||
items: children,
|
||||
}
|
||||
} else if (entry.isFile() && entry.name.endsWith('.md') && entry.name.toLowerCase() !== 'readme.md') {
|
||||
// 普通文件,取完整文件名作为链接
|
||||
sidebarItem = entry.name
|
||||
}
|
||||
|
||||
sidebarItemsWithOrder.push({ sidebarItem: sidebarItem, order: metaData.order })
|
||||
}
|
||||
sidebarItemsWithOrder.sort((a, b) => a.order - b.order)
|
||||
return sidebarItemsWithOrder.map((i) => i.sidebarItem)
|
||||
}
|
||||
|
||||
export function genNavigationComponents(
|
||||
locale: Locale,
|
||||
baseDir = path.resolve(__dirname, '../../'),
|
||||
): NavigationComponents {
|
||||
interface WrappedNavigationComponent {
|
||||
navItem: ThemeNavItem
|
||||
collectionItem: ThemeCollectionItem
|
||||
order: number
|
||||
}
|
||||
|
||||
const navigationComponentsWithOrder: WrappedNavigationComponent[] = []
|
||||
|
||||
// 进入指定语言目录,即docs/<i18n>/
|
||||
const langDir = path.join(baseDir, locale.name)
|
||||
|
||||
// 获取所有非隐藏文件和目录
|
||||
const entries = fs.readdirSync(langDir, { withFileTypes: true }).filter((e) => !e.name.startsWith('.'))
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue
|
||||
|
||||
const metaData = getMetaData(langDir, entry)
|
||||
if (!metaData) {
|
||||
continue
|
||||
}
|
||||
|
||||
const navbarItem: ThemeNavItem = {
|
||||
text: metaData.title,
|
||||
icon: metaData.icon,
|
||||
link: `/${locale.name}/${metaData.baseName}/`,
|
||||
}
|
||||
|
||||
const collectionItem: ThemeCollectionItem = {
|
||||
type: 'doc',
|
||||
title: metaData.title,
|
||||
dir: metaData.baseName,
|
||||
linkPrefix: `/${metaData.baseName}/`,
|
||||
sidebar: getSidebarItems(path.join(langDir, entry.name)),
|
||||
}
|
||||
|
||||
navigationComponentsWithOrder.push({
|
||||
navItem: navbarItem,
|
||||
collectionItem: collectionItem,
|
||||
order: metaData.order,
|
||||
})
|
||||
}
|
||||
|
||||
navigationComponentsWithOrder.sort((a, b) => a.order - b.order)
|
||||
|
||||
return {
|
||||
navbar: navigationComponentsWithOrder.map((i) => i.navItem),
|
||||
collections: navigationComponentsWithOrder.map((i) => i.collectionItem),
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
export interface Locale {
|
||||
name: string
|
||||
// displayName: string
|
||||
htmlLang: string
|
||||
siteTitle: string
|
||||
siteDescription: string
|
||||
}
|
||||
|
||||
export const locales: Locale[] = [
|
||||
{
|
||||
name: 'zh-cn',
|
||||
// displayName: '简体中文',
|
||||
htmlLang: 'zh-CN',
|
||||
siteTitle: 'MAA 文档站',
|
||||
siteDescription: '文档',
|
||||
},
|
||||
{
|
||||
name: 'zh-tw',
|
||||
// displayName: '繁體中文',
|
||||
htmlLang: 'zh-TW',
|
||||
siteTitle: 'MAA 文件站',
|
||||
siteDescription: '文件',
|
||||
},
|
||||
{
|
||||
name: 'en-us',
|
||||
// displayName: 'English',
|
||||
htmlLang: 'en-US',
|
||||
siteTitle: 'MAA Documentation Site',
|
||||
siteDescription: 'Documentation',
|
||||
},
|
||||
{
|
||||
name: 'ja-jp',
|
||||
// displayName: '日本語',
|
||||
htmlLang: 'ja-JP',
|
||||
siteTitle: 'MAA ドキュメントサイト',
|
||||
siteDescription: 'ドキュメント',
|
||||
},
|
||||
{
|
||||
name: 'ko-kr',
|
||||
// displayName: '한국어',
|
||||
htmlLang: 'ko-KR',
|
||||
siteTitle: 'MAA 문서 사이트',
|
||||
siteDescription: '문서',
|
||||
},
|
||||
]
|
||||
8
docs/.vuepress/notes/en-us.ts
Normal file
8
docs/.vuepress/notes/en-us.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineNotesConfig } from 'vuepress-theme-plume';
|
||||
import { genNotes } from './genSidebar';
|
||||
|
||||
export const enusNotes = defineNotesConfig({
|
||||
dir: 'en-us',
|
||||
link: '/en-us/',
|
||||
notes: genNotes('en-us'),
|
||||
});
|
||||
119
docs/.vuepress/notes/genSidebar.ts
Normal file
119
docs/.vuepress/notes/genSidebar.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as matterModule from 'gray-matter';
|
||||
import { defineNoteConfig, ThemeNote, ThemeSidebarItem } from 'vuepress-theme-plume';
|
||||
|
||||
const matter = (matterModule as any).default;
|
||||
|
||||
interface MetaData {
|
||||
baseName: string;
|
||||
order: number;
|
||||
title: string;
|
||||
icon: string;
|
||||
index: boolean;
|
||||
}
|
||||
|
||||
function getMetaData(dir: string, entry: fs.Dirent): MetaData | null {
|
||||
const currentPath = path.join(dir, entry.name);
|
||||
if (!fs.existsSync(currentPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let mdFilePath = '';
|
||||
if (entry.isDirectory()) {
|
||||
mdFilePath = path.join(currentPath, 'README.md');
|
||||
} else if (entry.isFile() && entry.name.endsWith('.md') && entry.name.toLowerCase() !== 'readme.md') {
|
||||
mdFilePath = currentPath;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(mdFilePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fileContent = fs.readFileSync(mdFilePath, 'utf-8');
|
||||
const meta = matter(fileContent).data ?? {};
|
||||
|
||||
const baseName = path.parse(entry.name).name;
|
||||
// 获取顺序,目录的order在meta.dir.order里,文件的order在meta.order里,默认值为一个大数
|
||||
const order = Number((entry.isDirectory() ? meta?.dir?.order : meta?.order) ?? Number.MAX_SAFE_INTEGER);
|
||||
// 获取标题,先从matter里找title,再用正则获取一级标题,最后fallback到文件名(不含扩展名)
|
||||
const title = String(meta?.title ?? RegExp('# (.+)').exec(fileContent)?.[1] ?? baseName);
|
||||
// 获取图标
|
||||
const icon = String(meta?.icon ?? '');
|
||||
// 是否作为索引页,文件永远为true,目录则看meta.index,默认true
|
||||
const index = entry.isDirectory() ? (Boolean(meta?.index) ?? true) : true;
|
||||
|
||||
return {
|
||||
baseName: baseName,
|
||||
order: order,
|
||||
title: title,
|
||||
icon: icon,
|
||||
index: index,
|
||||
};
|
||||
}
|
||||
|
||||
export function genNotes(lang: string, baseDir = path.resolve(__dirname, '../../')): ThemeNote[] {
|
||||
// 进入指定语言目录,即docs/<i18n>/
|
||||
const langDir = path.join(baseDir, lang);
|
||||
|
||||
// 递归获取目录和文件
|
||||
function getItems(dir: string, isRoot: boolean): any[] {
|
||||
// 将内容与对应顺序进行包装
|
||||
interface Wrapped {
|
||||
content: ThemeNote | ThemeSidebarItem | string;
|
||||
order: number;
|
||||
}
|
||||
let itemsWithOrder: Wrapped[] = [];
|
||||
|
||||
// 获取所有非隐藏文件和目录
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true }).filter((e) => !e.name.startsWith('.'));
|
||||
|
||||
for (const entry of entries) {
|
||||
const metaData = getMetaData(dir, entry);
|
||||
if (!metaData) {
|
||||
continue;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
// 递归获取子目录内容
|
||||
const children = getItems(path.join(dir, entry.name), false);
|
||||
|
||||
if (isRoot) {
|
||||
// 一级目录,作为“专题”
|
||||
const item = defineNoteConfig({
|
||||
dir: metaData.baseName,
|
||||
link: `/${metaData.baseName}/`,
|
||||
text: metaData.title,
|
||||
sidebar: children,
|
||||
});
|
||||
itemsWithOrder.push({ content: item, order: metaData.order });
|
||||
} else {
|
||||
// 非一级目录,作为可折叠的子目录
|
||||
const item: ThemeSidebarItem = {
|
||||
text: metaData.title,
|
||||
// 只有当目录设置了index: true时,才生成链接,否则点击时不跳转、只切换折叠状态
|
||||
link: metaData.index ? `${metaData.baseName}/` : undefined,
|
||||
icon: metaData.icon,
|
||||
// 目前没有文档使用了这个特性,故不处理
|
||||
// badge: undefined,
|
||||
collapsed: true,
|
||||
// 前面不能加斜杠,必须用相对路径
|
||||
prefix: `${metaData.baseName}/`,
|
||||
items: children,
|
||||
};
|
||||
itemsWithOrder.push({ content: item, order: metaData.order });
|
||||
}
|
||||
} else if (entry.isFile() && entry.name.endsWith('.md') && entry.name.toLowerCase() !== 'readme.md') {
|
||||
// 普通文件,取完整文件名作为链接
|
||||
const item = entry.name;
|
||||
itemsWithOrder.push({ content: item, order: metaData.order });
|
||||
}
|
||||
}
|
||||
// 当前dir的内容读取完毕,进行排序并返回,返回时丢弃order
|
||||
itemsWithOrder.sort((a, b) => a.order - b.order);
|
||||
return itemsWithOrder.map((i) => i.content);
|
||||
}
|
||||
// 递归起点,只有这里是一级目录,isRoot传true
|
||||
return getItems(langDir, true);
|
||||
}
|
||||
5
docs/.vuepress/notes/index.ts
Normal file
5
docs/.vuepress/notes/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './zh-cn';
|
||||
export * from './zh-tw';
|
||||
export * from './en-us';
|
||||
export * from './ja-jp';
|
||||
export * from './ko-kr';
|
||||
8
docs/.vuepress/notes/ja-jp.ts
Normal file
8
docs/.vuepress/notes/ja-jp.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineNotesConfig } from 'vuepress-theme-plume';
|
||||
import { genNotes } from './genSidebar';
|
||||
|
||||
export const jajpNotes = defineNotesConfig({
|
||||
dir: 'ja-jp',
|
||||
link: '/ja-jp/',
|
||||
notes: genNotes('ja-jp'),
|
||||
});
|
||||
8
docs/.vuepress/notes/ko-kr.ts
Normal file
8
docs/.vuepress/notes/ko-kr.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineNotesConfig } from 'vuepress-theme-plume';
|
||||
import { genNotes } from './genSidebar';
|
||||
|
||||
export const kokrNotes = defineNotesConfig({
|
||||
dir: 'ko-kr',
|
||||
link: '/ko-kr/',
|
||||
notes: genNotes('ko-kr'),
|
||||
});
|
||||
8
docs/.vuepress/notes/zh-cn.ts
Normal file
8
docs/.vuepress/notes/zh-cn.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineNotesConfig } from 'vuepress-theme-plume';
|
||||
import { genNotes } from './genSidebar';
|
||||
|
||||
export const zhcnNotes = defineNotesConfig({
|
||||
dir: 'zh-cn',
|
||||
link: '/zh-cn/',
|
||||
notes: genNotes('zh-cn'),
|
||||
});
|
||||
8
docs/.vuepress/notes/zh-tw.ts
Normal file
8
docs/.vuepress/notes/zh-tw.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineNotesConfig } from 'vuepress-theme-plume';
|
||||
import { genNotes } from './genSidebar';
|
||||
|
||||
export const zhtwNotes = defineNotesConfig({
|
||||
dir: 'zh-tw',
|
||||
link: '/zh-tw/',
|
||||
notes: genNotes('zh-tw'),
|
||||
});
|
||||
@@ -1,90 +0,0 @@
|
||||
const modules = import.meta.glob<string>('../../asciiArts/*.txt', { query: '?raw', import: 'default', eager: true })
|
||||
|
||||
const asciiArts: Record<string, string> = {}
|
||||
for (const path in modules) {
|
||||
const name = path
|
||||
.split('/')
|
||||
.pop()
|
||||
?.replace(/\.txt$/, '')!
|
||||
asciiArts[name] = modules[path]
|
||||
}
|
||||
|
||||
export type ThemeType = 'auto' | 'disable' | string
|
||||
export type AsciiArtScope = 'web' | 'console'
|
||||
interface AsciiArtData {
|
||||
name: string | null
|
||||
text: string
|
||||
}
|
||||
|
||||
function pickAsciiArt(
|
||||
arts: Record<string, string>,
|
||||
artFilter?: (key: string) => boolean,
|
||||
keyToName?: (key: string) => string,
|
||||
): AsciiArtData {
|
||||
const keys = artFilter ? Object.keys(arts).filter(artFilter) : Object.keys(arts)
|
||||
|
||||
let asciiArtKey: string | null
|
||||
let asciiArtText: string
|
||||
|
||||
if (keys.length === 0) {
|
||||
asciiArtKey = null
|
||||
asciiArtText = ''
|
||||
} else if (keys.length === 1) {
|
||||
asciiArtKey = keys[0]
|
||||
asciiArtText = arts[keys[0]]
|
||||
} else {
|
||||
const randomKey = keys[Math.floor(Math.random() * keys.length)]
|
||||
asciiArtKey = randomKey
|
||||
asciiArtText = arts[randomKey]
|
||||
}
|
||||
if (!asciiArtKey || !keyToName) {
|
||||
return { name: asciiArtKey, text: asciiArtText }
|
||||
} else {
|
||||
return { name: keyToName(asciiArtKey), text: asciiArtText }
|
||||
}
|
||||
}
|
||||
|
||||
export function getAsciiArt(name?: string, theme: ThemeType = 'auto', scope: AsciiArtScope = 'web'): AsciiArtData {
|
||||
let resolvedTheme: ThemeType = theme
|
||||
|
||||
// auto 模式
|
||||
if (theme === 'auto') {
|
||||
let currentTheme: string | null = null
|
||||
if (scope === 'web' && typeof document !== 'undefined') {
|
||||
// 浏览器中读取 HTML data-theme
|
||||
currentTheme = document?.documentElement?.getAttribute('data-theme')
|
||||
} else if (scope === 'console' && typeof window !== 'undefined' && window.matchMedia) {
|
||||
// fallback: 检查系统首选主题
|
||||
currentTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
resolvedTheme = currentTheme ? currentTheme : 'disable'
|
||||
}
|
||||
|
||||
if (resolvedTheme !== 'disable') {
|
||||
// light/dark/... 模式
|
||||
return name
|
||||
? pickAsciiArt(
|
||||
asciiArts,
|
||||
(k) => k === name + '.' + resolvedTheme,
|
||||
() => name,
|
||||
)
|
||||
: pickAsciiArt(
|
||||
asciiArts,
|
||||
(k) => k.endsWith('.' + resolvedTheme),
|
||||
(k) => k.replace(new RegExp('\\.' + resolvedTheme + '$'), ''),
|
||||
)
|
||||
} else {
|
||||
// disable 模式
|
||||
return name
|
||||
? pickAsciiArt(
|
||||
asciiArts,
|
||||
(k) => k === name || k.startsWith(name + '.'),
|
||||
() => name,
|
||||
)
|
||||
: pickAsciiArt(
|
||||
asciiArts,
|
||||
() => true,
|
||||
(k) => k,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
export default {
|
||||
provider: 'algolia' as const,
|
||||
appId: '9ARM1N4899',
|
||||
apiKey: 'f42bf1d18c786d5a46da30eccac5cb34',
|
||||
indexName: 'MaaAssistantArknights',
|
||||
appId: '99JM20SIFG',
|
||||
apiKey: '7596a5a8c95cd64d4cf3050c9a4f878e',
|
||||
indexName: 'maa',
|
||||
locales: {
|
||||
'/zh-cn/': {
|
||||
placeholder: '搜索',
|
||||
@@ -81,4 +81,4 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user