Improve style and tidiness, simplify nested namespace

This commit is contained in:
Horror Proton
2022-06-18 21:39:24 +08:00
parent a28220fe08
commit cfda9278a6
13 changed files with 374 additions and 400 deletions

View File

@@ -40,5 +40,4 @@ bool asst::AbstractConfiger::load(const std::string& filename)
m_last_error = std::string("json field error ") + e.what();
return false;
}
return true;
}

View File

@@ -170,12 +170,12 @@ bool AbstractTask::save_image(const cv::Mat& image, const std::string& dir)
bool asst::AbstractTask::need_exit() const
{
return m_exit_flag != nullptr && *m_exit_flag == true;
return m_exit_flag != nullptr && *m_exit_flag;
}
void asst::AbstractTask::callback(AsstMsg msg, const json::value& detail)
{
for (TaskPluginPtr plugin : m_plugins) {
for (const TaskPluginPtr& plugin : m_plugins) {
plugin->set_exit_flag(m_exit_flag);
plugin->set_ctrler(m_ctrler);
plugin->set_task_id(m_task_id);

View File

@@ -67,7 +67,7 @@ namespace asst
json::value basic_info_with_what(std::string what) const;
bool sleep(unsigned millisecond);
bool need_exit() const;
bool save_image(const cv::Mat& image, const std::string& dir);
static bool save_image(const cv::Mat& image, const std::string& dir);
bool m_enable = true;
bool m_ignore_error = true;

View File

@@ -82,43 +82,29 @@ asst::Assistant::TaskId asst::Assistant::append_task(const std::string& type, co
std::shared_ptr<PackageTask> ptr = nullptr;
if (type == FightTask::TaskType) {
ptr = std::make_shared<FightTask>(task_callback, static_cast<void*>(this));
}
else if (type == StartUpTask::TaskType) {
ptr = std::make_shared<StartUpTask>(task_callback, static_cast<void*>(this));
}
else if (type == AwardTask::TaskType) {
ptr = std::make_shared<AwardTask>(task_callback, static_cast<void*>(this));
}
else if (type == VisitTask::TaskType) {
ptr = std::make_shared<VisitTask>(task_callback, static_cast<void*>(this));
}
else if (type == MallTask::TaskType) {
ptr = std::make_shared<MallTask>(task_callback, static_cast<void*>(this));
}
else if (type == InfrastTask::TaskType) {
ptr = std::make_shared<InfrastTask>(task_callback, static_cast<void*>(this));
}
else if (type == RecruitTask::TaskType) {
ptr = std::make_shared<RecruitTask>(task_callback, static_cast<void*>(this));
}
else if (type == RoguelikeTask::TaskType) {
ptr = std::make_shared<RoguelikeTask>(task_callback, static_cast<void*>(this));
}
else if (type == CopilotTask::TaskType) {
ptr = std::make_shared<CopilotTask>(task_callback, static_cast<void*>(this));
}
#define ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(TASK) \
else if (type == TASK::TaskType) { ptr = std::make_shared<TASK>(task_callback, static_cast<void*>(this)); }
if (false) {}
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(FightTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(StartUpTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(AwardTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(VisitTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(MallTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(InfrastTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(RecruitTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(RoguelikeTask)
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(CopilotTask)
#ifdef ASST_DEBUG
else if (type == DebugTask::TaskType) {
ptr = std::make_shared<DebugTask>(task_callback, (void*)this);
}
ASST_ASSISTANT_APPEND_TASK_FROM_TYPE_IF_BRANCH(DebugTask)
#endif
else {
Log.error(__FUNCTION__, "| invalid type:", type);
return 0;
}
#undef ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH
bool params_ret = ptr->set_params(ret.value());
if (!params_ret) {
return 0;

View File

@@ -2,53 +2,50 @@
#include "AsstTypes.h"
namespace asst
namespace asst::infrast
{
namespace infrast
struct Facility
{
struct Facility
{
::std::string id;
::std::vector<::std::string> products;
int max_num_of_opers = 0;
};
::std::string id;
::std::vector<::std::string> products;
int max_num_of_opers = 0;
};
enum class SmileyType
{
Invalid = -1,
Rest, // 休息完成,绿色笑脸
Work, // 工作中,黄色笑脸
Distract // 注意力涣散,红色哭脸
};
struct Smiley
{
SmileyType type = SmileyType::Invalid;
Rect rect;
};
enum class Doing // 正在做什么
{
Invalid = -1,
Nothing, // 什么都不在做,也不在休息也不在工作
Resting, // 休息中
Working // 工作中
};
enum class SmileyType
{
Invalid = -1,
Rest, // 休息完成,绿色笑脸
Work, // 工作中,黄色笑脸
Distract // 注意力涣散,红色哭脸
};
struct Smiley
{
SmileyType type = SmileyType::Invalid;
Rect rect;
};
enum class Doing // 正在做什么
{
Invalid = -1,
Nothing, // 什么都不在做,也不在休息也不在工作
Resting, // 休息中
Working // 工作中
};
struct Skill
{
::std::string id;
::std::string templ_name;
::std::vector<::std::string> names; // 很多基建技能是一样的就是名字不同。所以一个技能id可能对应多个名字
::std::string desc;
::std::unordered_map<::std::string, double> efficient; // 技能效率key产品名赤金、经验书等, value: 效率数值
::std::unordered_map<::std::string, ::std::string> efficient_regex; // 技能效率正则key产品名赤金、经验书等, value: 效率正则。如不为空会先对正则进行计算再加上efficient里面的值
int max_num = INT_MAX; // 最多选几个该技能
struct Skill
{
::std::string id;
::std::string templ_name;
::std::vector<::std::string> names; // 很多基建技能是一样的就是名字不同。所以一个技能id可能对应多个名字
::std::string desc;
::std::unordered_map<::std::string, double> efficient; // 技能效率key产品名赤金、经验书等, value: 效率数值
::std::unordered_map<::std::string, ::std::string> efficient_regex; // 技能效率正则key产品名赤金、经验书等, value: 效率正则。如不为空会先对正则进行计算再加上efficient里面的值
int max_num = INT_MAX; // 最多选几个该技能
bool operator==(const Skill& skill) const noexcept
{
return id == skill.id;
}
};
}
bool operator==(const Skill& skill) const noexcept
{
return id == skill.id;
}
};
}
namespace std
@@ -64,67 +61,64 @@ namespace std
};
}
namespace asst
namespace asst::infrast
{
namespace infrast
struct BattleRealTimeOper
{
struct BattleRealTimeOper
{
::std::string face_hash; // 有些干员的技能是完全一样的做个hash区分一下不同干员
::std::string name_hash; // 预留
Smiley smiley;
double mood_ratio = 0; // 心情进度条的百分比
Doing doing = Doing::Invalid;
bool selected = false; // 干员是否已被选择(蓝色的选择框)
::std::unordered_set<Skill> skills;
Rect rect;
};
::std::string face_hash; // 有些干员的技能是完全一样的做个hash区分一下不同干员
::std::string name_hash; // 预留
Smiley smiley;
double mood_ratio = 0; // 心情进度条的百分比
Doing doing = Doing::Invalid;
bool selected = false; // 干员是否已被选择(蓝色的选择框)
::std::unordered_set<Skill> skills;
Rect rect;
};
struct SkillsComb
struct SkillsComb
{
SkillsComb() = default;
SkillsComb(std::unordered_set<Skill> skill_vec)
{
SkillsComb() = default;
SkillsComb(std::unordered_set<Skill> skill_vec)
{
skills = ::std::move(skill_vec);
for (const auto& s : skills) {
for (const auto& [key, value] : s.efficient) {
efficient[key] += value;
}
for (const auto& [key, reg] : s.efficient_regex) {
efficient_regex[key] += "+(" + reg + ")";
}
skills = ::std::move(skill_vec);
for (const auto& s : skills) {
for (const auto& [key, value] : s.efficient) {
efficient[key] += value;
}
for (const auto& [key, reg] : s.efficient_regex) {
efficient_regex[key] += "+(" + reg + ")";
}
}
bool operator==(const SkillsComb& rhs) const
{
return skills == rhs.skills;
}
::std::string desc;
::std::unordered_set<Skill> skills;
::std::unordered_map<std::string, double> efficient;
::std::unordered_map<std::string, ::std::string> efficient_regex;
::std::string name_hash;
bool hash_filter = false;
::std::unordered_map<std::string, ::std::string> possible_hashs; // 限定只允许某些hash匹配的某些干员。若hash不相同即使技能匹配了也不可用。hashs若为空则不生效
};
// 基建技能组
struct SkillsGroup
}
bool operator==(const SkillsComb& rhs) const
{
::std::string desc; // 文字介绍,实际不起作用
::std::unordered_map<std::string, int> conditions; // 技能组合可用条件例如key 发电站数量value 3
::std::vector<SkillsComb> necessary; // 必选技能。这里面的缺少任一,则该技能组合不可用
::std::vector<SkillsComb> optional; // 可选技能。
bool allow_external = false; // 当干员数没满3个的时候是否允许补充外部干员
};
return skills == rhs.skills;
}
enum class WorkMode
{
Invalid = -1,
Gentle, // 温和换班模式:会对干员人数不满的设施进行换班,计算单设施内最优解,尽量不破坏原有的干员组合;即若设施内干员是满的,则不对该设施进行换班
Aggressive, // 激进换班模式:会对每一个设施进行换班,计算单设施内最优解,但不会将其他设施中的干员替换过来;即按工作状态排序,仅选择前面的干员
Extreme // 偏激换班模式:会对每一个设施进行换班,计算全局的单设施内最优解,为追求更高效率,会将其他设施内的干员也替换过来;即按技能排序,计算所有拥有该设施技能的干员效率,无论他在不在其他地方工作
};
}
::std::string desc;
::std::unordered_set<Skill> skills;
::std::unordered_map<std::string, double> efficient;
::std::unordered_map<std::string, ::std::string> efficient_regex;
::std::string name_hash;
bool hash_filter = false;
::std::unordered_map<std::string, ::std::string> possible_hashs; // 限定只允许某些hash匹配的某些干员。若hash不相同即使技能匹配了也不可用。hashs若为空则不生效
};
// 基建技能组
struct SkillsGroup
{
::std::string desc; // 文字介绍,实际不起作用
::std::unordered_map<std::string, int> conditions; // 技能组合可用条件例如key 发电站数量value 3
::std::vector<SkillsComb> necessary; // 必选技能。这里面的缺少任一,则该技能组合不可用
::std::vector<SkillsComb> optional; // 可选技能。
bool allow_external = false; // 当干员数没满3个的时候是否允许补充外部干员
};
enum class WorkMode
{
Invalid = -1,
Gentle, // 温和换班模式:会对干员人数不满的设施进行换班,计算单设施内最优解,尽量不破坏原有的干员组合;即若设施内干员是满的,则不对该设施进行换班
Aggressive, // 激进换班模式:会对每一个设施进行换班,计算单设施内最优解,但不会将其他设施中的干员替换过来;即按工作状态排序,仅选择前面的干员
Extreme // 偏激换班模式:会对每一个设施进行换班,计算全局的单设施内最优解,为追求更高效率,会将其他设施内的干员也替换过来;即按技能排序,计算所有拥有该设施技能的干员效率,无论他在不在其他地方工作
};
}

View File

@@ -15,299 +15,296 @@
#include <memory.h>
#endif
namespace asst
namespace asst::utils
{
namespace utils
inline std::string string_replace_all(const std::string& src, const std::string& old_value, const std::string& new_value)
{
inline std::string string_replace_all(const std::string& src, const std::string& old_value, const std::string& new_value)
{
std::string str = src;
for (std::string::size_type pos(0); pos != std::string::npos; pos += new_value.length()) {
if ((pos = str.find(old_value, pos)) != std::string::npos)
str.replace(pos, old_value.length(), new_value);
else
break;
}
return str;
std::string str = src;
for (std::string::size_type pos(0); pos != std::string::npos; pos += new_value.length()) {
if ((pos = str.find(old_value, pos)) != std::string::npos)
str.replace(pos, old_value.length(), new_value);
else
break;
}
return str;
}
inline std::string string_replace_all_batch(const std::string& src, const std::vector<std::pair<std::string, std::string>>& replace_pairs)
{
std::string str = src;
for (auto& [old_value, new_value] : replace_pairs) {
str = string_replace_all(str, old_value, new_value);
}
return str;
inline std::string string_replace_all_batch(const std::string& src, const std::vector<std::pair<std::string, std::string>>& replace_pairs)
{
std::string str = src;
for (auto& [old_value, new_value] : replace_pairs) {
str = string_replace_all(str, old_value, new_value);
}
return str;
}
inline std::vector<std::string> string_split(const std::string& str, const std::string& delimiter)
{
std::string::size_type pos1 = 0;
std::string::size_type pos2 = str.find(delimiter);
std::vector<std::string> result;
inline std::vector<std::string> string_split(const std::string& str, const std::string& delimiter)
{
std::string::size_type pos1 = 0;
std::string::size_type pos2 = str.find(delimiter);
std::vector<std::string> result;
while (std::string::npos != pos2) {
result.emplace_back(str.substr(pos1, pos2 - pos1));
while (std::string::npos != pos2) {
result.emplace_back(str.substr(pos1, pos2 - pos1));
pos1 = pos2 + delimiter.size();
pos2 = str.find(delimiter, pos1);
}
if (pos1 != str.length())
result.emplace_back(str.substr(pos1));
return result;
pos1 = pos2 + delimiter.size();
pos2 = str.find(delimiter, pos1);
}
if (pos1 != str.length())
result.emplace_back(str.substr(pos1));
inline std::string get_format_time()
{
char buff[128] = { 0 };
return result;
}
inline std::string get_format_time()
{
char buff[128] = { 0 };
#ifdef _WIN32
SYSTEMTIME curtime;
GetLocalTime(&curtime);
SYSTEMTIME curtime;
GetLocalTime(&curtime);
#ifdef _MSC_VER
sprintf_s(buff, sizeof(buff),
sprintf_s(buff, sizeof(buff),
#else // ! _MSC_VER
sprintf(buff,
sprintf(buff,
#endif // END _MSC_VER
"%04d-%02d-%02d %02d:%02d:%02d.%03d",
curtime.wYear, curtime.wMonth, curtime.wDay,
curtime.wHour, curtime.wMinute, curtime.wSecond, curtime.wMilliseconds);
"%04d-%02d-%02d %02d:%02d:%02d.%03d",
curtime.wYear, curtime.wMonth, curtime.wDay,
curtime.wHour, curtime.wMinute, curtime.wSecond, curtime.wMilliseconds);
#else // ! _WIN32
struct timeval tv{};
gettimeofday(&tv, nullptr);
time_t nowtime = tv.tv_sec;
struct tm* tm_info = localtime(&nowtime);
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", tm_info);
sprintf(buff, "%s.%03ld", buff, tv.tv_usec / 1000);
struct timeval tv{};
gettimeofday(&tv, nullptr);
time_t nowtime = tv.tv_sec;
struct tm* tm_info = localtime(&nowtime);
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", tm_info);
sprintf(buff, "%s.%03ld", buff, tv.tv_usec / 1000);
#endif // END _WIN32
return buff;
}
return buff;
}
inline std::string ansi_to_utf8(const std::string& ansi_str)
{
inline std::string ansi_to_utf8(const std::string& ansi_str)
{
#ifdef _WIN32
const char* src_str = ansi_str.c_str();
int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, nullptr, 0);
const std::size_t wstr_length = static_cast<std::size_t>(len) + 1U;
auto wstr = new wchar_t[wstr_length];
memset(wstr, 0, sizeof(wstr[0]) * wstr_length);
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
const char* src_str = ansi_str.c_str();
int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, nullptr, 0);
const std::size_t wstr_length = static_cast<std::size_t>(len) + 1U;
auto wstr = new wchar_t[wstr_length];
memset(wstr, 0, sizeof(wstr[0]) * wstr_length);
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
const std::size_t str_length = static_cast<std::size_t>(len) + 1;
auto str = new char[str_length];
memset(str, 0, sizeof(str[0]) * str_length);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, nullptr, nullptr);
std::string strTemp = str;
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
const std::size_t str_length = static_cast<std::size_t>(len) + 1;
auto str = new char[str_length];
memset(str, 0, sizeof(str[0]) * str_length);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, nullptr, nullptr);
std::string strTemp = str;
delete[] wstr;
wstr = nullptr;
delete[] str;
str = nullptr;
delete[] wstr;
wstr = nullptr;
delete[] str;
str = nullptr;
return strTemp;
return strTemp;
#else // Don't fucking use gbk in linux!
return ansi_str;
return ansi_str;
#endif
}
}
inline std::string utf8_to_ansi(const std::string& utf8_str)
{
inline std::string utf8_to_ansi(const std::string& utf8_str)
{
#ifdef _WIN32
const char* src_str = utf8_str.c_str();
int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, nullptr, 0);
const std::size_t wsz_ansi_length = static_cast<std::size_t>(len) + 1;
auto wsz_ansi = new wchar_t[wsz_ansi_length];
memset(wsz_ansi, 0, sizeof(wsz_ansi[0]) * wsz_ansi_length);
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wsz_ansi, len);
const char* src_str = utf8_str.c_str();
int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, nullptr, 0);
const std::size_t wsz_ansi_length = static_cast<std::size_t>(len) + 1;
auto wsz_ansi = new wchar_t[wsz_ansi_length];
memset(wsz_ansi, 0, sizeof(wsz_ansi[0]) * wsz_ansi_length);
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wsz_ansi, len);
len = WideCharToMultiByte(CP_ACP, 0, wsz_ansi, -1, nullptr, 0, nullptr, nullptr);
const std::size_t sz_ansi_length = static_cast<std::size_t>(len) + 1;
auto sz_ansi = new char[sz_ansi_length];
memset(sz_ansi, 0, sizeof(sz_ansi[0]) * sz_ansi_length);
WideCharToMultiByte(CP_ACP, 0, wsz_ansi, -1, sz_ansi, len, nullptr, nullptr);
std::string strTemp(sz_ansi);
len = WideCharToMultiByte(CP_ACP, 0, wsz_ansi, -1, nullptr, 0, nullptr, nullptr);
const std::size_t sz_ansi_length = static_cast<std::size_t>(len) + 1;
auto sz_ansi = new char[sz_ansi_length];
memset(sz_ansi, 0, sizeof(sz_ansi[0]) * sz_ansi_length);
WideCharToMultiByte(CP_ACP, 0, wsz_ansi, -1, sz_ansi, len, nullptr, nullptr);
std::string strTemp(sz_ansi);
delete[] wsz_ansi;
wsz_ansi = nullptr;
delete[] sz_ansi;
sz_ansi = nullptr;
delete[] wsz_ansi;
wsz_ansi = nullptr;
delete[] sz_ansi;
sz_ansi = nullptr;
return strTemp;
return strTemp;
#else // Don't fucking use gbk in linux!
return utf8_str;
return utf8_str;
#endif
}
template <typename RetTy, typename ArgType>
constexpr inline RetTy make_rect(const ArgType& rect)
{
return RetTy{ rect.x, rect.y, rect.width, rect.height };
}
inline std::string load_file_without_bom(const std::string& filename)
{
std::ifstream ifs(filename, std::ios::in);
if (!ifs.is_open()) {
return {};
}
std::stringstream iss;
iss << ifs.rdbuf();
ifs.close();
std::string str = iss.str();
template <typename RetTy, typename ArgType>
constexpr inline RetTy make_rect(const ArgType& rect)
{
return RetTy{ rect.x, rect.y, rect.width, rect.height };
}
using uchar = unsigned char;
constexpr static uchar Bom_0 = 0xEF;
constexpr static uchar Bom_1 = 0xBB;
constexpr static uchar Bom_2 = 0xBF;
inline std::string load_file_without_bom(const std::string& filename)
{
std::ifstream ifs(filename, std::ios::in);
if (!ifs.is_open()) {
return {};
}
std::stringstream iss;
iss << ifs.rdbuf();
ifs.close();
std::string str = iss.str();
using uchar = unsigned char;
constexpr static uchar Bom_0 = 0xEF;
constexpr static uchar Bom_1 = 0xBB;
constexpr static 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 str;
}
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 str;
}
return str;
}
inline std::string callcmd(const std::string& cmdline)
{
constexpr int PipeBuffSize = 4096;
std::string pipe_str;
auto pipe_buffer = std::make_unique<char[]>(PipeBuffSize);
inline std::string callcmd(const std::string& cmdline)
{
constexpr int PipeBuffSize = 4096;
std::string pipe_str;
auto pipe_buffer = std::make_unique<char[]>(PipeBuffSize);
#ifdef _WIN32
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipe_sec_attr.lpSecurityDescriptor = nullptr;
pipe_sec_attr.bInheritHandle = TRUE;
HANDLE pipe_read = nullptr;
HANDLE pipe_child_write = nullptr;
CreatePipe(&pipe_read, &pipe_child_write, &pipe_sec_attr, PipeBuffSize);
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipe_sec_attr.lpSecurityDescriptor = nullptr;
pipe_sec_attr.bInheritHandle = TRUE;
HANDLE pipe_read = nullptr;
HANDLE pipe_child_write = nullptr;
CreatePipe(&pipe_read, &pipe_child_write, &pipe_sec_attr, PipeBuffSize);
STARTUPINFOA si = { 0 };
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = pipe_child_write;
si.hStdError = pipe_child_write;
STARTUPINFOA si = { 0 };
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = pipe_child_write;
si.hStdError = pipe_child_write;
PROCESS_INFORMATION pi = { nullptr };
PROCESS_INFORMATION pi = { nullptr };
BOOL p_ret = CreateProcessA(nullptr, const_cast<LPSTR>(cmdline.c_str()), nullptr, nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi);
if (p_ret) {
DWORD peek_num = 0;
DWORD read_num = 0;
do {
while (::PeekNamedPipe(pipe_read, nullptr, 0, nullptr, &peek_num, nullptr) && peek_num > 0) {
if (::ReadFile(pipe_read, pipe_buffer.get(), peek_num, &read_num, nullptr)) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
}
}
} while (::WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT);
DWORD exit_ret = 255;
::GetExitCodeProcess(pi.hProcess, &exit_ret);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
::CloseHandle(pipe_read);
::CloseHandle(pipe_child_write);
#else
constexpr static int PIPE_READ = 0;
constexpr static int PIPE_WRITE = 1;
int pipe_in[2] = { 0 };
int pipe_out[2] = { 0 };
int pipe_in_ret = pipe(pipe_in);
int pipe_out_ret = pipe(pipe_out);
fcntl(pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
int exit_ret = 0;
int child = fork();
if (child == 0) {
// child process
dup2(pipe_in[PIPE_READ], STDIN_FILENO);
dup2(pipe_out[PIPE_WRITE], STDOUT_FILENO);
dup2(pipe_out[PIPE_WRITE], STDERR_FILENO);
// all these are for use by parent only
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
exit_ret = execlp("sh", "sh", "-c", cmdline.c_str(), nullptr);
exit(exit_ret);
}
else if (child > 0) {
// parent process
// close unused file descriptors, these are for child only
close(pipe_in[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
do {
ssize_t read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
while (read_num > 0) {
BOOL p_ret = CreateProcessA(nullptr, const_cast<LPSTR>(cmdline.c_str()), nullptr, nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi);
if (p_ret) {
DWORD peek_num = 0;
DWORD read_num = 0;
do {
while (::PeekNamedPipe(pipe_read, nullptr, 0, nullptr, &peek_num, nullptr) && peek_num > 0) {
if (::ReadFile(pipe_read, pipe_buffer.get(), peek_num, &read_num, nullptr)) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
};
} while (::waitpid(child, &exit_ret, WNOHANG) == 0);
}
}
} while (::WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
}
else {
// failed to create child process
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
}
#endif
return pipe_str;
DWORD exit_ret = 255;
::GetExitCodeProcess(pi.hProcess, &exit_ret);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
// template<typename T,
// typename = typename std::enable_if<std::is_constructible<T, std::string>::value>::type>
// std::string VectorToString(const std::vector<T>& vector, bool to_gbk = false) {
// if (vector.empty()) {
// return std::string();
// }
// static const std::string inter = ", ";
// std::string str;
// for (const T& ele : vector) {
// if (to_gbk) {
// str += utils::utf8_to_ansi(ele) + inter;
// }
// else {
// str += ele + inter;
// }
// }
::CloseHandle(pipe_read);
::CloseHandle(pipe_child_write);
// if (!str.empty()) {
// str.erase(str.size() - inter.size(), inter.size());
// }
// return str;
//}
#else
constexpr static int PIPE_READ = 0;
constexpr static int PIPE_WRITE = 1;
int pipe_in[2] = { 0 };
int pipe_out[2] = { 0 };
int pipe_in_ret = pipe(pipe_in);
int pipe_out_ret = pipe(pipe_out);
fcntl(pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
int exit_ret = 0;
int child = fork();
if (child == 0) {
// child process
dup2(pipe_in[PIPE_READ], STDIN_FILENO);
dup2(pipe_out[PIPE_WRITE], STDOUT_FILENO);
dup2(pipe_out[PIPE_WRITE], STDERR_FILENO);
//template<typename T,
// typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
// std::string VectorToString(const std::vector<T>& vector) {
// if (vector.empty()) {
// return std::string();
// }
// static const std::string inter = ", ";
// std::string str;
// for (const T& ele : vector) {
// str += std::to_string(ele) + inter;
// }
// all these are for use by parent only
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
// if (!str.empty()) {
// str.erase(str.size() - inter.size(), inter.size());
// }
// return str;
//}
exit_ret = execlp("sh", "sh", "-c", cmdline.c_str(), nullptr);
exit(exit_ret);
}
else if (child > 0) {
// parent process
// close unused file descriptors, these are for child only
close(pipe_in[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
do {
ssize_t read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
while (read_num > 0) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
};
} while (::waitpid(child, &exit_ret, WNOHANG) == 0);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
}
else {
// failed to create child process
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
}
#endif
return pipe_str;
}
// template<typename T,
// typename = typename std::enable_if<std::is_constructible<T, std::string>::value>::type>
// std::string VectorToString(const std::vector<T>& vector, bool to_gbk = false) {
// if (vector.empty()) {
// return std::string();
// }
// static const std::string inter = ", ";
// std::string str;
// for (const T& ele : vector) {
// if (to_gbk) {
// str += utils::utf8_to_ansi(ele) + inter;
// }
// else {
// str += ele + inter;
// }
// }
// if (!str.empty()) {
// str.erase(str.size() - inter.size(), inter.size());
// }
// return str;
//}
//template<typename T,
// typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
// std::string VectorToString(const std::vector<T>& vector) {
// if (vector.empty()) {
// return std::string();
// }
// static const std::string inter = ", ";
// std::string str;
// for (const T& ele : vector) {
// str += std::to_string(ele) + inter;
// }
// if (!str.empty()) {
// str.erase(str.size() - inter.size(), inter.size());
// }
// return str;
//}
}

View File

@@ -57,7 +57,7 @@ private:
asst::Controller::Controller(AsstCallback callback, void* callback_arg)
: m_callback(std::move(callback)),
m_callback_arg(callback_arg),
m_rand_engine(static_cast<unsigned int>(time(nullptr)))
m_rand_engine(std::random_device{}())
{
LogTraceFunction;
@@ -242,7 +242,7 @@ void asst::Controller::pipe_working_proc()
}
}
std::optional<std::vector<unsigned char>> asst::Controller::call_command(const std::string& cmd, int64_t timeout, bool recv_by_socket)
std::optional<std::vector<uchar>> asst::Controller::call_command(const std::string& cmd, int64_t timeout, bool recv_by_socket)
{
LogTraceScope(std::string(__FUNCTION__) + " | `" + cmd + "`");
@@ -400,20 +400,19 @@ std::optional<std::vector<unsigned char>> asst::Controller::call_command(const s
return std::nullopt;
}
void asst::Controller::convert_lf(std::vector<unsigned char>& data)
void asst::Controller::convert_lf(std::vector<uchar>& data)
{
LogTraceFunction;
if (data.empty() || data.size() < 2) {
return;
}
using Iter = std::vector<unsigned char>::iterator;
auto pred = [](const Iter& cur) -> bool {
auto pred = [](const std::vector<uchar>::iterator& cur) -> bool {
return *cur == '\r' && *(cur + 1) == '\n';
};
// find the first of "\r\n"
Iter first_iter = data.end();
for (Iter iter = data.begin(); iter != data.end() - 1; ++iter) {
auto first_iter = data.end();
for (auto iter = data.begin(); iter != data.end() - 1; ++iter) {
if (pred(iter)) {
first_iter = iter;
break;
@@ -423,8 +422,8 @@ void asst::Controller::convert_lf(std::vector<unsigned char>& data)
return;
}
// move forward all non-crlf elements
Iter end_r1_iter = data.end() - 1;
Iter next_iter = first_iter;
auto end_r1_iter = data.end() - 1;
auto next_iter = first_iter;
while (++first_iter != end_r1_iter) {
if (!pred(first_iter)) {
*next_iter = *first_iter;
@@ -464,7 +463,7 @@ void asst::Controller::random_delay() const
auto& opt = Resrc.cfg().get_options();
if (opt.control_delay_upper != 0) {
LogTraceFunction;
static std::default_random_engine rand_engine(static_cast<unsigned int>(time(nullptr)));
static std::default_random_engine rand_engine(std::random_device{}());
static std::uniform_int_distribution<unsigned> rand_uni(
opt.control_delay_lower,
opt.control_delay_upper);
@@ -500,7 +499,7 @@ int asst::Controller::push_cmd(const std::string& cmd)
std::unique_lock<std::mutex> lock(m_cmd_queue_mutex);
m_cmd_queue.emplace(cmd);
m_cmd_condvar.notify_one();
return ++m_push_id;
return int(++m_push_id);
}
std::optional<unsigned short> asst::Controller::try_to_init_socket(const std::string& local_address, unsigned short try_port, unsigned short try_times)
@@ -635,7 +634,7 @@ bool asst::Controller::screencap()
{
Log.info("Try to find the fastest way to screencap");
m_inited = false;
auto min_cost = std::chrono::nanoseconds(MAXLONGLONG);
auto min_cost = std::chrono::nanoseconds(LLONG_MAX);
auto start_time = std::chrono::high_resolution_clock::now();
if (m_support_socket && m_server_started &&
@@ -1168,8 +1167,6 @@ bool asst::Controller::release()
#ifndef _WIN32
if (m_child)
#else
if (true)
#endif
{
return call_command(m_adb.release).has_value();

View File

@@ -64,7 +64,7 @@ namespace asst
private:
void pipe_working_proc();
std::optional<std::vector<unsigned char>> call_command(const std::string& cmd, int64_t timeout = 20000, bool recv_by_socket = false);
std::optional<std::vector<uchar>> call_command(const std::string& cmd, int64_t timeout = 20000, bool recv_by_socket = false);
int push_cmd(const std::string& cmd);
std::optional<unsigned short> try_to_init_socket(const std::string& local_address, unsigned short try_port, unsigned short try_times = 10U);
@@ -81,7 +81,7 @@ namespace asst
void clear_info() noexcept;
// 转换data中所有的crlf为lf有些模拟器自带的adbexec-out输出的\n会被替换成\r\n导致解码错误所以这里转一下回来点名批评mumu
static void convert_lf(std::vector<unsigned char>& data);
static void convert_lf(std::vector<uchar>& data);
AsstCallback m_callback;
void* m_callback_arg = nullptr;

View File

@@ -10,7 +10,7 @@ bool asst::InfrastConfiger::parse(const json::value& json)
for (const json::value& facility : json.at("facility").as_array()) {
std::string facility_name = facility.as_string();
json::value facility_json = json.at(facility_name);
const json::value& facility_json = json.at(facility_name);
std::vector<std::string> products;
for (const json::value& product_json : facility_json.at("products").as_array()) {

View File

@@ -5,6 +5,7 @@
#include <iostream>
#include <mutex>
#include <type_traits>
#include <utility>
#include <vector>
#include <thread>
@@ -202,8 +203,8 @@ namespace asst
class LoggerAux
{
public:
LoggerAux(const std::string& func_name)
: m_func_name(func_name),
LoggerAux(std::string func_name)
: m_func_name(std::move(func_name)),
m_start_time(std::chrono::steady_clock::now())
{
Logger::get_instance().trace(m_func_name, " | enter");

View File

@@ -33,7 +33,7 @@ asst::ProcessTask::ProcessTask(AbstractTask&& abs, std::vector<std::string> task
bool asst::ProcessTask::run()
{
if (!m_enable) {
Log.info("task is disable, pass", basic_info().to_string());
Log.info("task disabled, pass", basic_info().to_string());
return true;
}
if (m_task_delay == TaskDelayUnsetted) {

View File

@@ -9,7 +9,7 @@
#include "TemplResource.h"
#include "Logger.hpp"
const std::shared_ptr<asst::TaskInfo> asst::TaskData::get(const std::string& name) const noexcept
std::shared_ptr<const asst::TaskInfo> asst::TaskData::get(const std::string& name) const noexcept
{
if (auto iter = m_all_tasks_info.find(name);
iter != m_all_tasks_info.cend()) {
@@ -35,7 +35,7 @@ bool asst::TaskData::parse(const json::value& json)
LogTraceFunction;
auto to_lower = [](char c) -> char {
return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
return char(std::tolower(c));
};
for (const auto& [name, task_json] : json.as_object()) {
std::string algorithm_str = task_json.get("algorithm", "matchtemplate");

View File

@@ -18,14 +18,14 @@ namespace asst
virtual ~TaskData() = default;
static TaskData& get_instance()
static TaskData& get_instance() noexcept
{
static TaskData unique_instance;
return unique_instance;
}
const std::unordered_set<std::string>& get_templ_required() const noexcept;
const std::shared_ptr<TaskInfo> get(const std::string& name) const noexcept;
std::shared_ptr<const TaskInfo> get(const std::string& name) const noexcept;
std::shared_ptr<TaskInfo> get(const std::string& name);
protected: