Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 新增动作 Command #463

Merged
merged 10 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 56 additions & 1 deletion docs/en_us/3.1-PipelineProtocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ This loop continues until the "next" of a task is empty, which signifies that th

- `action`: *string*
Action to execute. Optional, default is `DoNothing`.
Possible values: `DoNothing` | `Click` | `Swipe` | `MultiSwipe` | `Key` | `InputText` | `StartApp` | `StopApp` | `StopTask` | `Custom`.
Possible values: `DoNothing` | `Click` | `Swipe` | `MultiSwipe` | `Key` | `InputText` | `StartApp` | `StopApp` | `StopTask` | `Command` | `Custom`.
See [Action Types](#action-types) for details.

- `next`: *string* | *list<string, >*
Expand Down Expand Up @@ -553,6 +553,61 @@ Additional properties for this action:

Stops the current task chain (the individual task chain passed to MaaTaskerPostPipeline).

### `Command`

Execute a command.

This action attribute requires additional fields:

- `exec`: *string*
The path of the program to be executed. Required.

- `args`: *list<string,>*
The arguments to be executed. Optional.
supports runtime parameters replacement:

- `{ENTRY}`: Entry name.
- `{NODE}`: Node name.
- `{IMAGE}`: The path to the file where the screenshot is saved. The file is deleted before the process exits. Please copy it by yourself if you want to save it permanently.
- `{BOX}`: Identify the hit target, the format is `[x, y, w, h]`.
- `{RESOURCE_DIR}`: The path of the resource folder loaded last time.
- `{LIBRARY_DIR}`: The path of the folder where the MaaFW library is located.

- `detach`: *bool*
Detach the child process, that is, do not wait for the child process to complete, and directly continue with the subsequent tasks. Optional, default false.

Example:

```jsonc
{
"TaskA": {
"action": "Command",
"exec": "Python",
"args": [
"{RESOURCE_DIR}/my_script/test.py"
"Haha",
"{IMAGE}",
"{NODE}",
"{BOX}"
]
},
"TaskB": {
"action": "Command",
"exec": "{RESOURCE_DIR}/my_exec/my_exec.exe"
}
}
```

The actual command is:

```bash
# TaskA
Python C:/MaaXXX/resource/my_script/test.py Haha C:/temp/123.png TaskA [0,0,0,0]

# TaskB
C:/MaaXXX/resource/my_exec/my_exec.exe
```

### `Custom`

Execute the action handle passed in through the `MaaResourceRegisterCustomAction` interface
Expand Down
57 changes: 56 additions & 1 deletion docs/zh_cn/3.1-任务流水线协议.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Orange 的 next 中,

- `action`: *string*
执行的动作。可选,默认 `DoNothing` 。
可选的值:`DoNothing` | `Click` | `Swipe` | `MultiSwipe` | `Key` | `InputText` | `StartApp` | `StopApp` | `StopTask` | `Custom`
可选的值:`DoNothing` | `Click` | `Swipe` | `MultiSwipe` | `Key` | `InputText` | `StartApp` | `StopApp` | `StopTask` | `Command` | `Custom`
详见 [动作类型](#动作类型)。

- `next` : *string* | *list<string, >*
Expand Down Expand Up @@ -563,6 +563,61 @@ Orange 的 next 中,

停止当前任务链(MaaTaskerPostPipeline 传入的单个任务链)。

### `Command`

执行命令。

该动作属性需额外部分字段:

- `exec`: *string*
执行的程序路径。必选。

- `args`: *list<string,>*
执行的参数。可选。
支持部分运行期参数替换:

- `{ENTRY}`: 任务入口名。
- `{NODE}`: 当前任务名。
- `{IMAGE}`: 截图保存到文件的路径。该文件在进程退出前删除,若要持久保存请自行复制。
- `{BOX}`: 识别命中的目标,格式为 `[x, y, w, h]`。
- `{RESOURCE_DIR}`: 最后一次加载的资源文件夹路径。
- `{LIBRARY_DIR}`: MaaFW 库所在的文件夹路径。

- `detach`: *bool*
分离子进程,即不等待子进程执行完成,直接继续之后后面的任务。可选,默认 false。

举例:

```jsonc
{
"TaskA": {
"action": "Command",
"exec": "Python",
"args": [
"{RESOURCE_DIR}/my_script/test.py"
"Haha",
"{IMAGE}",
"{NODE}",
"{BOX}"
]
},
"TaskB": {
"action": "Command",
"exec": "{RESOURCE_DIR}/my_exec/my_exec.exe"
}
}
```

实际将会执行命令

```bash
# TaskA
Python C:/MaaXXX/resource/my_script/test.py Haha C:/temp/123.png TaskA [0,0,0,0]

# TaskB
C:/MaaXXX/resource/my_exec/my_exec.exe
```

### `Custom`

执行通过 `MaaResourceRegisterCustomAction` 接口传入的动作句柄。
Expand Down
15 changes: 4 additions & 11 deletions source/MaaAdbControlUnit/Base/ProcessArgvGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,15 @@ std::optional<ProcessArgvGenerator::ProcessArgv> ProcessArgvGenerator::gen(const
string_replace_all_(s, replacement);
}

std::filesystem::path abs_path;
if (auto raw_path = MAA_NS::path(res.front()); raw_path.is_absolute()) {
abs_path = raw_path;
}
else {
abs_path = boost::process::search_path(raw_path);
}

if (!std::filesystem::exists(abs_path)) {
LogError << "exec path not exists" << VAR(abs_path);
std::filesystem::path exec = boost::process::search_path(path(res.front()));
if (!std::filesystem::exists(exec)) {
LogError << "exec path not exists" << VAR(res.front()) << VAR(exec);
return std::nullopt;
}

auto args = std::vector(std::make_move_iterator(res.begin() + 1), std::make_move_iterator(res.end()));

return ProcessArgv { .exec = std::move(abs_path), .args = std::move(args) };
return ProcessArgv { .exec = std::move(exec), .args = std::move(args) };
}

MAA_CTRL_UNIT_NS_END
2 changes: 2 additions & 0 deletions source/MaaFramework/Resource/DefaultPipelineMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ bool DefaultPipelineMgr::parse_action(const json::value& input)
{ "startapp", Type::StartApp },
{ "StopApp", Type::StopApp },
{ "stopapp", Type::StopApp },
{ "Command", Type::Command },
{ "command", Type::Command },
{ "Custom", Type::Custom },
{ "custom", Type::Custom },
{ "StopTask", Type::StopTask },
Expand Down
36 changes: 34 additions & 2 deletions source/MaaFramework/Resource/PipelineResMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,8 @@ bool PipelineResMgr::parse_action(
{ "startapp", Type::StartApp },
{ "StopApp", Type::StopApp },
{ "stopapp", Type::StopApp },
{ "Command", Type::Command },
{ "command", Type::Command },
{ "Custom", Type::Custom },
{ "custom", Type::Custom },
{ "StopTask", Type::StopTask },
Expand Down Expand Up @@ -1176,7 +1178,8 @@ bool PipelineResMgr::parse_action(
return parse_multi_swipe(
input,
std::get<MultiSwipeParam>(out_param),
same_type ? std::get<MultiSwipeParam>(parent_param) : default_multi, default_single);
same_type ? std::get<MultiSwipeParam>(parent_param) : default_multi,
default_single);
} break;

case Type::Key: {
Expand All @@ -1203,14 +1206,23 @@ bool PipelineResMgr::parse_action(
return parse_app_info(input, std::get<AppParam>(out_param), same_type ? std::get<AppParam>(parent_param) : default_param);
} break;

case Type::Command: {
auto default_param = default_mgr.get_action_param<CommandParam>(Type::Command);
out_param = default_param;
return parse_command_param(
input,
std::get<CommandParam>(out_param),
same_type ? std::get<CommandParam>(parent_param) : default_param);
} break;

case Type::Custom: {
auto default_param = default_mgr.get_action_param<CustomParam>(Type::Custom);
out_param = default_param;
return parse_custom_action_param(
input,
std::get<CustomParam>(out_param),
same_type ? std::get<CustomParam>(parent_param) : default_param);
}
} break;

case Type::StopTask:
out_param = {};
Expand Down Expand Up @@ -1326,6 +1338,26 @@ bool PipelineResMgr::parse_app_info(const json::value& input, Action::AppParam&
return true;
}

bool PipelineResMgr::parse_command_param(const json::value& input, Action::CommandParam& output, const Action::CommandParam& default_value)
{
if (!get_and_check_value(input, "exec", output.exec, default_value.exec)) {
LogError << "failed to get_and_check_value exec" << VAR(input);
return false;
}

if (!get_and_check_value_or_array(input, "args", output.args, default_value.args)) {
LogError << "failed to get_and_check_value args" << VAR(input);
return false;
}

if (!get_and_check_value(input, "detach", output.detach, default_value.detach)) {
LogError << "failed to get_and_check_value detach" << VAR(input);
return false;
}

return true;
}

bool PipelineResMgr::parse_custom_action_param(
const json::value& input,
Action::CustomParam& output,
Expand Down
1 change: 1 addition & 0 deletions source/MaaFramework/Resource/PipelineResMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class PipelineResMgr : public NonCopyable
static bool parse_press_key(const json::value& input, Action::KeyParam& output, const Action::KeyParam& default_value);
static bool parse_input_text(const json::value& input, Action::TextParam& output, const Action::TextParam& default_value);
static bool parse_app_info(const json::value& input, Action::AppParam& output, const Action::AppParam& default_value);
static bool parse_command_param(const json::value& input, Action::CommandParam& output, const Action::CommandParam& default_value);
static bool parse_custom_action_param(const json::value& input, Action::CustomParam& output, const Action::CustomParam& default_value);

static bool parse_wait_freezes_param(
Expand Down
10 changes: 9 additions & 1 deletion source/MaaFramework/Resource/PipelineTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ enum class Type
Text,
StartApp,
StopApp,
Command,
Custom,
StopTask,
};
Expand Down Expand Up @@ -95,14 +96,21 @@ struct AppParam
std::string package;
};

struct CommandParam
{
std::string exec;
std::vector<std::string> args;
bool detach = false;
};

struct CustomParam
{
std::string name;
json::value custom_param;
Target target;
};

using Param = std::variant<std::monostate, ClickParam, SwipeParam, MultiSwipeParam, KeyParam, TextParam, AppParam, CustomParam>;
using Param = std::variant<std::monostate, ClickParam, SwipeParam, MultiSwipeParam, KeyParam, TextParam, AppParam, CommandParam, CustomParam>;
} // namespace Action

struct WaitFreezesParam
Expand Down
2 changes: 2 additions & 0 deletions source/MaaFramework/Resource/ResourceMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class ResourceMgr : public MaaResource

const auto& default_pipeline() const { return default_pipeline_; }

const std::vector<std::filesystem::path>& paths() const { return paths_; }

CustomRecognitionSession custom_recognition(const std::string& name) const;
CustomActionSession custom_action(const std::string& name) const;

Expand Down
32 changes: 31 additions & 1 deletion source/MaaFramework/Task/Component/Actuator.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "Actuator.h"

#include "CommandAction.h"
#include "Controller/ControllerAgent.h"
#include "CustomAction.h"
#include "Utils/Logger.h"
Expand All @@ -13,7 +14,7 @@ Actuator::Actuator(Tasker* tasker, Context& context)
{
}

bool Actuator::run(const cv::Rect& reco_hit, MaaRecoId reco_id, const PipelineData& pipeline_data)
bool Actuator::run(const cv::Rect& reco_hit, MaaRecoId reco_id, const PipelineData& pipeline_data, const std::string& entry)
{
using namespace MAA_RES_NS::Action;
LogFunc << VAR(pipeline_data.name);
Expand Down Expand Up @@ -52,6 +53,9 @@ bool Actuator::run(const cv::Rect& reco_hit, MaaRecoId reco_id, const PipelineDa
case Type::StopApp:
ret = stop_app(std::get<AppParam>(pipeline_data.action_param));
break;
case Type::Command:
ret = command(std::get<CommandParam>(pipeline_data.action_param), reco_hit, pipeline_data.name, entry);
break;
case Type::Custom:
ret = custom_action(std::get<CustomParam>(pipeline_data.action_param), reco_hit, reco_id, pipeline_data.name);
break;
Expand Down Expand Up @@ -217,6 +221,32 @@ bool Actuator::stop_app(const MAA_RES_NS::Action::AppParam& param)
return controller()->stop_app(param.package);
}

bool Actuator::command(
const MAA_RES_NS::Action::CommandParam& param,
const cv::Rect& box,
const std::string& name,
const std::string& entry)
{
if (!controller()) {
LogError << "Controller is null";
return false;
}
auto* resource = tasker_ ? tasker_->resource() : nullptr;
if (!resource) {
LogError << "Resource is null";
return false;
}

CommandAction::Runtime rt {
.resource_paths = resource->paths(),
.entry = entry,
.node = name,
.image = controller()->cached_image(),
.box = box,
};
return CommandAction().run(param, rt);
}

bool Actuator::custom_action(const MAA_RES_NS::Action::CustomParam& param, const cv::Rect& box, MaaRecoId reco_id, const std::string& name)
{
if (!tasker_) {
Expand Down
6 changes: 2 additions & 4 deletions source/MaaFramework/Task/Component/Actuator.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#pragma once

#include <stack>
#include <string_view>

#include <meojson/json.hpp>

#include "API/MaaTypes.h"
Expand All @@ -23,7 +20,7 @@ class Actuator
public:
Actuator(Tasker* tasker, Context& context);

bool run(const cv::Rect& reco_hit, MaaRecoId reco_id, const PipelineData& pipeline_data);
bool run(const cv::Rect& reco_hit, MaaRecoId reco_id, const PipelineData& pipeline_data, const std::string& entry);

private:
bool click(const MAA_RES_NS::Action::ClickParam& param, const cv::Rect& box);
Expand All @@ -34,6 +31,7 @@ class Actuator

bool start_app(const MAA_RES_NS::Action::AppParam& param);
bool stop_app(const MAA_RES_NS::Action::AppParam& param);
bool command(const MAA_RES_NS::Action::CommandParam& param, const cv::Rect& box, const std::string& name, const std::string& entry);
bool custom_action(const MAA_RES_NS::Action::CustomParam& param, const cv::Rect& box, MaaRecoId reco_id, const std::string& name);

void wait_freezes(const MAA_RES_NS::WaitFreezesParam& param, const cv::Rect& box);
Expand Down
Loading
Loading