mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-07 21:40:31 +08:00
Compare commits
3 Commits
archive/de
...
docs/task-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78c1ff3a5c | ||
|
|
53052833f4 | ||
|
|
cd17cced22 |
@@ -189,6 +189,3 @@ UseTab: Never
|
||||
# VerilogBreakBetweenInstancePorts:
|
||||
# WhitespaceSensitiveMacros:
|
||||
RemoveEmptyLinesInUnwrappedLines: true
|
||||
---
|
||||
Language: ObjC
|
||||
BasedOnStyle: "WebKit"
|
||||
|
||||
5
.clangd
5
.clangd
@@ -1,5 +0,0 @@
|
||||
CompileFlags:
|
||||
CompilationDatabase: build
|
||||
Add: [-Wunused-variables]
|
||||
Diagnostics:
|
||||
UnusedIncludes: None
|
||||
@@ -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
|
||||
|
||||
@@ -10,6 +10,3 @@ end_of_line = lf
|
||||
[*.json]
|
||||
|
||||
indent_size = 4
|
||||
|
||||
[*.makefile]
|
||||
indent_style = tab
|
||||
|
||||
@@ -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
|
||||
|
||||
21
.github/ISSUE_TEMPLATE/cn-bug-report.yaml
vendored
21
.github/ISSUE_TEMPLATE/cn-bug-report.yaml
vendored
@@ -41,10 +41,11 @@ body:
|
||||
attributes:
|
||||
label: 日志和配置文件
|
||||
description: |
|
||||
**请在 MAA -> 设置 -> 问题反馈中找到生成日志压缩包按钮,点击并上传压缩包**
|
||||
**若待上传压缩包大于 25MB,请转而上传该压缩包同日期文件夹中的若干小压缩包**
|
||||
**若为 MAA 闪退问题,如果 %LOCALAPPDATA%\CrashDumps 中存在 MAA.exe.dmp 文件,请一并上传**
|
||||
若正在使用 macOS,请点击屏幕左上角的“文件”,点击“打开日志文件夹”
|
||||
**请在 MAA -> 设置 -> 问题反馈中找到生成日志压缩包按钮,点击并上传压缩包**
|
||||
|
||||
**请直接将完整的文件拖拽进来,而非自己裁切或复制的片段;若文件体积过大可压缩后再上传**
|
||||
|
||||
如果你在使用 MacBook,请点击屏幕左上角的“文件”,点击“打开日志文件夹”
|
||||
placeholder: |
|
||||
请确认上传文件前已关闭 MAA
|
||||
validations:
|
||||
@@ -54,8 +55,8 @@ body:
|
||||
attributes:
|
||||
label: 配置信息
|
||||
description: |
|
||||
请说明操作系统及版本、模拟器品牌、模拟器分辨率、DPI、帧率
|
||||
若正在使用 MuMu 或雷电 9,请说明截图增强是否开启
|
||||
请说明操作系统及版本、模拟器品牌、模拟器分辨率、DPI、帧率;
|
||||
若正在使用 MuMu 或雷电 9,请说明截图增强是否开启;
|
||||
最后请说明 GPU 加速推理是否开启,若开启请提供 GPU 型号。
|
||||
validations:
|
||||
required: true
|
||||
@@ -64,9 +65,11 @@ body:
|
||||
attributes:
|
||||
label: 截图或录屏
|
||||
description: |
|
||||
可上传屏幕截图或录制以帮助解释你的问题,包括但不限于 MAA 软件截图、游戏画面截图
|
||||
若是**识别相关问题**,请尽可能提供模拟器自带的截图工具截取的无遮挡的**原图**(或通过 adb 截取原图)
|
||||
用其他的工具(如QQ/微信)截取的图片包含窗口边框且长宽比、分辨率不固定,不利于我们排除bug
|
||||
`debug` 目录下按功能分类的文件夹内,有一些自动截图的错误图片,若有相关的,请一并打包上传
|
||||
|
||||
可上传屏幕截图或录制以帮助解释你的问题,包括但不限于 MAA 软件截图、游戏画面截图
|
||||
若是**识别相关问题**,请尽可能提供模拟器自带的截图工具截取的无遮挡的**原图**(或通过 adb 截取原图)
|
||||
用其他的工具(如QQ/微信)截取的图片包含窗口边框且长宽比、分辨率不固定,不利于我们排除bug
|
||||
若文件体积过大可压缩后再上传
|
||||
validations:
|
||||
required: false
|
||||
|
||||
26
.github/ISSUE_TEMPLATE/en-bug-report.yaml
vendored
26
.github/ISSUE_TEMPLATE/en-bug-report.yaml
vendored
@@ -43,10 +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 the issue is related to MAA crashing, please upload the MAA.exe.dmp file found in %LOCALAPPDATA%\CrashDumps if it exists**
|
||||
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:
|
||||
@@ -56,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
|
||||
@@ -66,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:
|
||||
|
||||
26
.github/issue-checker.yml
vendored
26
.github/issue-checker.yml
vendored
@@ -129,12 +129,6 @@ labels:
|
||||
- name: remove client-ZH_TW
|
||||
content:
|
||||
regexes: "[Rr]emove (?:[Ll]abels? |)(?:`|)(?:[Cc]li(?:ent|): |)ZH_TW(?:`|)"
|
||||
- name: skip client-PC
|
||||
content:
|
||||
regexes: "[Ss]kip (?:[Ll]abels? |)(?:`|)(?:[Cc]li(?:ent|): |)PC(?:`|)"
|
||||
- name: remove client-PC
|
||||
content:
|
||||
regexes: "[Rr]emove (?:[Ll]abels? |)(?:`|)(?:[Cc]li(?:ent|): |)PC(?:`|)"
|
||||
|
||||
- name: skip ambiguous
|
||||
content:
|
||||
@@ -258,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
|
||||
@@ -341,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
|
||||
@@ -414,18 +408,6 @@ labels:
|
||||
- remove client
|
||||
- remove client-ZH_TW
|
||||
|
||||
# `client: PC`
|
||||
- name: "client: PC"
|
||||
regexes: '(?:[Pp][Cc]|[Ww]indows|[Ww]in)\s*(?:版|端|客户端)'
|
||||
skip-if:
|
||||
- skip all
|
||||
- skip client
|
||||
- skip client-PC
|
||||
remove-if:
|
||||
- remove all
|
||||
- remove client
|
||||
- remove client-PC
|
||||
|
||||
# `ambiguous`
|
||||
- name: pr-ambiguous
|
||||
# 不符合 commitizen 的 PR
|
||||
@@ -540,7 +522,7 @@ labels:
|
||||
# `incomplete`
|
||||
- name: incomplete
|
||||
content: incomplete
|
||||
regexes: '(?:\[Uploading asst(?:.bak|)(?: - 副本|)(?:.log|)(?:.zip|)…\]\(\))|<!-- (?:Failed to upload|Uploading) "(log|report)[^"]*\.zip"(?:\.\.\.)? -->'
|
||||
regexes: '(?:\[Uploading asst(?:.bak|)(?: - 副本|)(?:.log|)(?:.zip|)…\]\(\))|<!-- Uploading "(log|report)[^"]*\.zip"\.\.\. -->'
|
||||
mode: add
|
||||
skip-if:
|
||||
- skip all
|
||||
@@ -565,7 +547,7 @@ labels:
|
||||
|
||||
comments:
|
||||
- name: Log upload failed
|
||||
regexes: '(?:\[Uploading asst(?:.bak|)(?: - 副本|)(?:.log|)(?:.zip|)…\]\(\))|<!-- (?:Failed to upload|Uploading) "(log|report)[^"]*\.zip"(?:\.\.\.)? -->'
|
||||
regexes: '\[Uploading asst(?:.bak|)(?: - 副本|)(?:.log|)(?:.zip|)…\]\(\)|<!-- Uploading "log[^"]*\.zip"\.\.\. -->'
|
||||
content: "你的日志没有上传成功,请重新上传。\n\n\
|
||||
Your log did not upload successfully, please re-upload it."
|
||||
mode: add
|
||||
|
||||
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@v7
|
||||
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@v7
|
||||
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@v7
|
||||
- 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@v7
|
||||
- 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@v7
|
||||
- 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@v8
|
||||
- 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@v8
|
||||
- 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@v7
|
||||
- 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@v7
|
||||
- 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@v8
|
||||
- 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
|
||||
|
||||
25
.github/workflows/markdown-checker.yml
vendored
25
.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,24 +30,23 @@ 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:
|
||||
# 仅检查内部链接,排除所有外部链接
|
||||
args: >
|
||||
--root-dir ./docs/.vuepress/public
|
||||
--verbose --no-progress
|
||||
--cache --max-cache-age 1d --cache-exclude-status '429, 500..599'
|
||||
--exclude 'https?://.*'
|
||||
|
||||
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@v7
|
||||
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@v7
|
||||
- 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@v8
|
||||
- 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@v7
|
||||
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@v8
|
||||
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 }}
|
||||
204
.github/workflows/res-update-game.yml
vendored
204
.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@v7
|
||||
- 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@v7
|
||||
- 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@v7
|
||||
- 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
|
||||
@@ -155,27 +142,20 @@ jobs:
|
||||
|
||||
- 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: |
|
||||
./tools/ResourceUpdater/libopencv_world4.4.11.0.dylib
|
||||
./tools/ResourceUpdater/res_updater
|
||||
|
||||
- name: Fetch submodules
|
||||
if: steps.resupd-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git submodule update --init --depth 1 src/MaaUtils
|
||||
|
||||
- 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
|
||||
@@ -185,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 macos-arm64
|
||||
cmake --build --preset 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@v8
|
||||
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@v8
|
||||
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@v8
|
||||
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
|
||||
@@ -249,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'
|
||||
@@ -257,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') }}
|
||||
@@ -277,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: |
|
||||
@@ -327,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@v7
|
||||
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@v7
|
||||
- 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"
|
||||
|
||||
16
.gitignore
vendored
16
.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/*
|
||||
@@ -475,10 +475,6 @@ Thumbs.db
|
||||
# build & install
|
||||
build
|
||||
install
|
||||
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
|
||||
175
CHANGELOG.md
175
CHANGELOG.md
@@ -1,150 +1,49 @@
|
||||
## v6.4.1-beta.1
|
||||
|
||||
### 何忆卫? | Highlight
|
||||
|
||||
这一版更新不大,但都是提升使用体验的改动~
|
||||
|
||||
#### 自动战斗优化
|
||||
|
||||
在这个版本,我们优化了自动战斗的多项体验:
|
||||
|
||||
* 我们针对没有跳过按钮的对话流程进行了优化,使其能被正确处理,跳过对话后能继续保留二倍速状态;
|
||||
* 现在其他活动选项卡也支持加载作业集,可通过作业列表快捷切换不同作业(仅支持手动切换,不支持如主线/SideStory 的多作业连续作战)。
|
||||
|
||||
我们还优化了其他内容。
|
||||
|
||||
#### 功能适配
|
||||
|
||||
在这个版本,我们支持了国服的游戏内暂停期间可部署干员的功能。
|
||||
|
||||
国际服方面,我们新增了对国际服次生预案自动刷取的支持,还是那句话:「次生预案」玩法类似《循环勇士》,带有种田要素,越早布置生产产线,就能越早挂机产出资源。不要等到最后一天再开始刷,会来不及。
|
||||
|
||||
我们新增了对国际服“齐聚”主题的支持。
|
||||
|
||||
对于游戏 MAC 端,我们也适配了 PlayCover 的 BGR 优化截图。
|
||||
|
||||
对于游戏 PC 端,由于其安全策略限制,如果需要牛牛控制 PC 端,则需要以管理员身份运行 MAA。 ~~(不是终末地那个咕咕嘎嘎小企鹅)~~
|
||||
|
||||
> ⚠️ 注意:控制 PC 端时仍需保持游戏窗口**不能**最小化,并且目前仅支持真实鼠标点击(不能模拟,会抢鼠标)。
|
||||
|
||||
#### 其他方面
|
||||
|
||||
我们优化了包括自动检测连接、每次重新检测、PC 端连接设置、自动编队忽略干员属性要求等多处文本描述,以便你更好地理解相关内容。
|
||||
|
||||
---
|
||||
|
||||
This update is minor, but all changes improve the user experience.
|
||||
|
||||
#### _Copilot_ Optimization
|
||||
|
||||
In this version, we've optimized several aspects of the _Copilot_ experience:
|
||||
|
||||
* We've optimized dialogue flows without a skip button, ensuring they are handled correctly and that the 2x speed mode is retained after skipping dialogue.
|
||||
|
||||
* _Other Activities_ tabs now support loading job sets, allowing quick switching between different jobs via the Job List (manual switching only; continuous multi-job operation like in MainTheme/SideStory is not supported).
|
||||
|
||||
We've also optimized other content.
|
||||
|
||||
#### Feature Adaptation
|
||||
|
||||
**\[CN ONLY\]** In this version, we support the ability to deploy operators during in-game pauses in the Chinese server.
|
||||
|
||||
**\[GLOBAL ONLY\]** We've added support for automatic farming of _Rebuilding Mandate_. As mentioned before, _Rebuilding Mandate_ is similar to _Loop Hero_, with resource-gathering elements. The sooner you set up your resource production in the stages, the sooner you can start passively generating resources. Don't wait until the last day to start farming; it will be too late.
|
||||
|
||||
**\[GLOBAL ONLY\]** We've added support for the _Together_ theme.
|
||||
|
||||
For the Mac version of the game, we've also adapted PlayCover's BGR-optimized screenshots.
|
||||
|
||||
For the PC version of the game, due to its security policy restrictions, if you need MAA to control the PC version, you need to run MAA as an administrator. ~~(Not the Endministrator from the Endfield)~~
|
||||
|
||||
> ⚠️ Note: When controlling the PC version, the game window **must not** be minimized, and currently only real mouse clicks are supported (simulated clicks are not supported, and MAA will take over mouse control to perform automatic clicks).
|
||||
|
||||
#### Other Aspects
|
||||
|
||||
We have optimized several text descriptions, including _Auto detect connection_, _Re-detect every times_, _Connection_ setting for PC version of the game, and _Ignore Operator requirements_ for _Auto Squad_, to help you better understand the relevant content.
|
||||
|
||||
---
|
||||
|
||||
### 以下是详细内容:
|
||||
|
||||
## v6.4.1-beta.1
|
||||
## v5.26.0-beta.1
|
||||
|
||||
### 新增 | New
|
||||
|
||||
* macOS ScreenCaptureKit (#15939) @hguandl
|
||||
|
||||
### 改进 | Improved
|
||||
|
||||
* 新Config属性变动log 优化 @status102
|
||||
* 当热更资源命中时, 不再二次加载资源 (#15907) @status102
|
||||
* RM SettlementStageName roi @Daydreamer114
|
||||
* 次生预案十里坡剑神 @ABA2396
|
||||
* 设置指引添加更新设置 @ABA2396
|
||||
* 设置指引添加性能设置 @ABA2396
|
||||
|
||||
### 修复 | Fix
|
||||
|
||||
* jp tag ocr @Saratoga-Official
|
||||
* KR RM WaitForEnd @Daydreamer114
|
||||
* EN RM SettlementStageName (#15946) @Daydreamer114
|
||||
* 文档首页语言选择按钮的宽度定义方式 (#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
|
||||
|
||||
* MuMu Screenshot i18n @ABA2396
|
||||
* 在 MuMu 截图增强模式中加入国际版 (#15934) @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
|
||||
|
||||
* 调整主线/资源收集模板阈值 @ABA2396
|
||||
* 调整干员识别部分角色字体颜色及排序 @ABA2396
|
||||
|
||||
## v6.4.0
|
||||
|
||||
### 新增 | New
|
||||
|
||||
* 调整 mumu 国际版截图增强支持提示 @ABA2396
|
||||
* 合并 `处于战斗中` 检测, 增加倍速记忆, 支持战斗中不带跳过按钮的带头像对话教程 (#15706) @status102
|
||||
* 设置界面选项页允许折叠 @ABA2396
|
||||
* PC 端运行时要求以管理员身份重启 MAA (#15748) @SherkeyXD
|
||||
* 自动战斗-其他活动支持使用作业列表加载作业集并从中选择作业 (#15804) @status102
|
||||
* JP RebuildingMandate and Together theme (#15931) @Manicsteiner
|
||||
* YostarEN RebuildingMandate + Together @Constrat
|
||||
|
||||
### 改进 | Improved
|
||||
|
||||
* 优化自动检测连接与每次重新检测连接提示 @ABA2396
|
||||
* ASST_DEBUG 在 lazy_parse 后不再重新生成任务信息 (#15895) @status102
|
||||
* scopeLog 记录函数进出时间 @status102
|
||||
* TaskQueue 任务属性变更记录路径优化 @status102
|
||||
* 适配国服游戏内暂停期间部署 (#15888) @status102
|
||||
* 适配 PlayCover 的 BGR 优化截图 (#15810) @hguandl
|
||||
* EN, JP, KR MiniGame AT「相談室‧御影」小遊戲 (#15870) @Daydreamer114
|
||||
* optimize png @Constrat
|
||||
|
||||
### 修复 | Fix
|
||||
|
||||
* 修复今日关卡小提示中奶盾芯片数量顺序错误 @ABA2396
|
||||
* 移除不必要的配置迁移触发条件 @status102
|
||||
* 修改任务名过滤换行 @status102
|
||||
* Fix YoStarJP Sidestory GO OCR error (#15906) @JasonHuang79
|
||||
* Make Starting Operator searching dropdown case insensitive for en (#15879) @Zenith00
|
||||
|
||||
### 文档 | Docs
|
||||
|
||||
* 使文档站中侧边栏的功能介绍板块默认展开 (#15927) @lucienshawls
|
||||
|
||||
### 其他 | Other
|
||||
|
||||
* 调整每次重新检测勾选框选中时的颜色 @ABA2396
|
||||
* 繁中服「墟」導航文字 (#15925) @momomochi987
|
||||
* `战斗列表` 选项更名为 `多作业模式`, 以区分于作业容器 (#15913) @status102 @Constrat @HX3N @Manicsteiner
|
||||
* 更正最小化的描述 @MistEO
|
||||
* 调整 PC 端输入选项及描述 @MistEO
|
||||
* ClientType 常量替换 @status102
|
||||
* 剿灭 string 常量 @status102
|
||||
* 刷理智筛选候选关卡后在日志中记录 @status102
|
||||
* 自动战斗协议 `干员技能默认值` 变更为 0 (不指定技能) (#15898) @status102
|
||||
* 自动战斗跳过干员属性要求提示 增加 `精英化例外` 及 `跳过后不点赞说明` (#15881) @status102 @Constrat @HX3N @momomochi987
|
||||
* macOS build scripts (#15936) @hguandl
|
||||
* MaaDeps cache asset (#15933) @hguandl
|
||||
* KR RebuildingMandate ocr edit @HX3N
|
||||
* EN Rebuilding Mandate @Constrat
|
||||
* KR RebuildingMandate and Together UiTheme (#15932) @HX3N
|
||||
* cleanup warnings - unused variables and unused includes @Constrat
|
||||
* 统一显示效果 @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)
|
||||
@@ -10,40 +15,37 @@ option(INSTALL_PYTHON "install python ffi" OFF)
|
||||
option(INSTALL_RESOURCE "install resource" OFF)
|
||||
option(INSTALL_FLATTEN "do not use bin lib include directory" ON)
|
||||
option(WITH_EMULATOR_EXTRAS "build with emulator extras" ${WIN32})
|
||||
option(WITH_MAC_SCK "build with macOS ScreenCaptureKit" ${APPLE})
|
||||
option(WITH_HASH_VERSION "generate version from git hash" OFF)
|
||||
option(BUILD_RESOURCE_UPDATER "build resource updater tool" 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"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$<CONFIG>"
|
||||
)
|
||||
add_dependencies(run-MaaWpfGui MaaCore MaaWpfGui)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(INSTALL_PYTHON)
|
||||
@@ -57,7 +59,3 @@ endif()
|
||||
if(BUILD_DEBUG_DEMO OR BUILD_SMOKE_TEST)
|
||||
add_subdirectory(src/Cpp)
|
||||
endif()
|
||||
|
||||
if(BUILD_RESOURCE_UPDATER)
|
||||
add_subdirectory(tools/ResourceUpdater)
|
||||
endif()
|
||||
|
||||
@@ -1,403 +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",
|
||||
"BUILD_RESOURCE_UPDATER": "ON",
|
||||
"INSTALL_RESOURCE": "OFF",
|
||||
"INSTALL_PYTHON": "OFF"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-clang-base",
|
||||
"hidden": true,
|
||||
"generator": "Ninja Multi-Config",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"$comment": [
|
||||
"NOT for building — only for generating compile_commands.json for clangd / VS Code",
|
||||
"run from 'x64 Native Tools Command Prompt for VS' or ensure clang-cl is in PATH",
|
||||
"to build, use the Visual Studio presets (windows-x64, windows-arm64)"
|
||||
],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang-cl",
|
||||
"CMAKE_CXX_COMPILER": "clang-cl",
|
||||
"CMAKE_C_COMPILER_TARGET": "x86_64-pc-windows-msvc",
|
||||
"CMAKE_CXX_COMPILER_TARGET": "x86_64-pc-windows-msvc",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
|
||||
"BUILD_WPF_GUI": "OFF",
|
||||
"BUILD_DEBUG_DEMO": "ON",
|
||||
"BUILD_RESOURCE_UPDATER": "ON",
|
||||
"INSTALL_RESOURCE": "OFF",
|
||||
"INSTALL_PYTHON": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-x64-clang",
|
||||
"inherits": "windows-clang-base",
|
||||
"displayName": "Windows x64 (clang-cl)",
|
||||
"cacheVariables": {
|
||||
"MAADEPS_TRIPLET": "maa-x64-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"
|
||||
}
|
||||
]
|
||||
}
|
||||
30
README.md
30
README.md
@@ -21,10 +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>
|
||||
<a href="https://trendshift.io/repositories/979" target="_blank"><img src="https://trendshift.io/api/badge/repositories/979" alt="MaaAssistantArknights%2FMaaAssistantArknights | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
<br>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
@@ -47,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)
|
||||
- 支持手动识别公招界面,方便对高星公招做出选择 ~~(你的这个高资回费出的是推王呢还是推王呢)~~
|
||||
@@ -102,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)
|
||||
|
||||
@@ -114,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)
|
||||
@@ -132,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,83 +1,27 @@
|
||||
# This file is no longer used in the official build process,
|
||||
# but is kept for reference and potential future use.
|
||||
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,163 +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
|
||||
collapsed?: 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 ?? '')
|
||||
// 是否添加链接,对文件无效(总会为文件添加链接),目录则看meta.index,默认值为true
|
||||
const index = entry.isDirectory() ? Boolean(meta?.index ?? true) : undefined
|
||||
// 是否默认折叠,对文件无效(文件没有折叠的概念),目录则看meta.collapsed,默认值为true
|
||||
const collapsed = entry.isDirectory() ? Boolean(meta?.collapsed ?? true) : undefined
|
||||
|
||||
return {
|
||||
baseName: baseName,
|
||||
order: order,
|
||||
title: title,
|
||||
icon: icon,
|
||||
index: index,
|
||||
collapsed: collapsed,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
collapsed: metaData.collapsed,
|
||||
// 前面不能加斜杠,必须用相对路径
|
||||
prefix: `${metaData.baseName}/`,
|
||||
items: children,
|
||||
}
|
||||
} else {
|
||||
// 普通文件,取完整文件名作为链接
|
||||
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'),
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user