mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-20 10:57:45 +08:00
Merge pull request #1676 from MaaAssistantArknights/style/code_tidy
style: code tidy
This commit is contained in:
189
.clang-format
Normal file
189
.clang-format
Normal file
@@ -0,0 +1,189 @@
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: false
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
# RequiresClausePosition: OwnLine # clang-format 15
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 50
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: c++20
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
@@ -19,7 +19,7 @@ bool asst::AbstractConfiger::load(const std::string& filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
//std::string content = utils::load_file_without_bom(filename);
|
||||
// std::string content = utils::load_file_without_bom(filename);
|
||||
|
||||
auto&& ret = json::open(filename, true);
|
||||
if (!ret) {
|
||||
|
||||
@@ -9,17 +9,16 @@
|
||||
asst::AbstractImageAnalyzer::AbstractImageAnalyzer(const cv::Mat& image)
|
||||
: m_image(image), m_roi(empty_rect_to_full(Rect(), image))
|
||||
#ifdef ASST_DEBUG
|
||||
,
|
||||
m_image_draw(image.clone())
|
||||
,
|
||||
m_image_draw(image.clone())
|
||||
#endif
|
||||
{}
|
||||
|
||||
asst::AbstractImageAnalyzer::AbstractImageAnalyzer(const cv::Mat& image, const Rect& roi)
|
||||
: m_image(image),
|
||||
m_roi(empty_rect_to_full(roi, image))
|
||||
: m_image(image), m_roi(empty_rect_to_full(roi, image))
|
||||
#ifdef ASST_DEBUG
|
||||
,
|
||||
m_image_draw(image.clone())
|
||||
,
|
||||
m_image_draw(image.clone())
|
||||
#endif
|
||||
{}
|
||||
|
||||
@@ -69,7 +68,7 @@ asst::Rect asst::AbstractImageAnalyzer::empty_rect_to_full(const Rect& rect, con
|
||||
bool asst::AbstractImageAnalyzer::save_img()
|
||||
{
|
||||
std::string stem = utils::get_format_time();
|
||||
stem = utils::string_replace_all_batch(stem, { {":", "-"}, {" ", "_"} });
|
||||
stem = utils::string_replace_all_batch(stem, { { ":", "-" }, { " ", "_" } });
|
||||
std::filesystem::create_directory("debug");
|
||||
bool ret = cv::imwrite("debug/" + stem + "_raw.png", m_image);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "NoWarningCVMat.h"
|
||||
#include "AsstTypes.h"
|
||||
#include "NoWarningCVMat.h"
|
||||
|
||||
//#ifndef ASST_DEBUG
|
||||
//#define ASST_DEBUG
|
||||
|
||||
@@ -14,10 +14,7 @@ namespace asst
|
||||
virtual ~AbstractResource() = default;
|
||||
|
||||
virtual bool load(const std::string& filename) = 0;
|
||||
virtual const std::string& get_last_error() const noexcept
|
||||
{
|
||||
return m_last_error;
|
||||
}
|
||||
virtual const std::string& get_last_error() const noexcept { return m_last_error; }
|
||||
|
||||
AbstractResource& operator=(const AbstractResource& rhs) = delete;
|
||||
AbstractResource& operator=(AbstractResource&& rhs) noexcept = delete;
|
||||
|
||||
@@ -2,25 +2,23 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "NoWarningCV.h"
|
||||
|
||||
#include "AbstractTaskPlugin.h"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Controller.h"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
#include "AbstractTaskPlugin.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "Resource.h"
|
||||
|
||||
using namespace asst;
|
||||
|
||||
AbstractTask::AbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain)
|
||||
: m_callback(std::move(callback)),
|
||||
m_callback_arg(callback_arg),
|
||||
m_task_chain(std::move(task_chain))
|
||||
: m_callback(std::move(callback)), m_callback_arg(callback_arg), m_task_chain(std::move(task_chain))
|
||||
{}
|
||||
|
||||
bool asst::AbstractTask::run()
|
||||
@@ -113,7 +111,7 @@ json::value asst::AbstractTask::basic_info() const
|
||||
task_name = class_name;
|
||||
}
|
||||
|
||||
m_basic_info_cache = json::object{
|
||||
m_basic_info_cache = json::object {
|
||||
{ "taskchain", m_task_chain },
|
||||
{ "taskid", m_task_id },
|
||||
{ "class", class_name },
|
||||
@@ -193,7 +191,7 @@ void asst::AbstractTask::click_return_button()
|
||||
void asst::AbstractTask::save_image()
|
||||
{
|
||||
std::string stem = utils::get_format_time();
|
||||
stem = utils::string_replace_all_batch(stem, { {":", "-"}, {" ", "_"} });
|
||||
stem = utils::string_replace_all_batch(stem, { { ":", "-" }, { " ", "_" } });
|
||||
std::filesystem::create_directory("debug");
|
||||
cv::imwrite("debug/" + stem + "_raw.png", m_ctrler->get_image());
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <meojson/json.hpp>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <meojson/json.hpp>
|
||||
|
||||
#include "AsstMsg.h"
|
||||
|
||||
@@ -39,9 +39,9 @@ namespace asst
|
||||
virtual AbstractTask& set_ignore_error(bool ignore) noexcept;
|
||||
virtual AbstractTask& set_task_id(int task_id) noexcept;
|
||||
|
||||
template<typename PluginType>
|
||||
std::shared_ptr<PluginType> register_plugin()
|
||||
requires std::derived_from<PluginType, AbstractTaskPlugin> // Plugin must inherit AbstractTaskPlugin
|
||||
template <typename PluginType>
|
||||
std::shared_ptr<PluginType> register_plugin() requires
|
||||
std::derived_from<PluginType, AbstractTaskPlugin> // Plugin must inherit AbstractTaskPlugin
|
||||
{
|
||||
auto plugin = std::make_shared<PluginType>(m_callback, m_callback_arg, m_task_chain);
|
||||
m_plugins.emplace(plugin);
|
||||
@@ -56,6 +56,7 @@ namespace asst
|
||||
virtual json::value basic_info() const;
|
||||
|
||||
constexpr static int RetryTimesDefault = 20;
|
||||
|
||||
protected:
|
||||
virtual bool _run() = 0;
|
||||
virtual bool on_run_fails() { return true; }
|
||||
@@ -82,4 +83,4 @@ namespace asst
|
||||
std::shared_ptr<Controller> m_ctrler = nullptr;
|
||||
std::shared_ptr<RuntimeStatus> m_status = nullptr;
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "AsstMsg.h"
|
||||
#include "AbstractTask.h"
|
||||
#include "AsstMsg.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
@@ -27,7 +27,6 @@ namespace asst
|
||||
bool operator==(const AbstractTaskPlugin& rhs) const;
|
||||
|
||||
protected:
|
||||
|
||||
AbstractTask* m_task_ptr = nullptr;
|
||||
int m_priority = 0;
|
||||
bool m_block = false;
|
||||
|
||||
@@ -10,26 +10,24 @@
|
||||
#include "Resource.h"
|
||||
#include "RuntimeStatus.h"
|
||||
|
||||
#include "FightTask.h"
|
||||
#include "StartUpTask.h"
|
||||
#include "CloseDownTask.h"
|
||||
#include "AwardTask.h"
|
||||
#include "VisitTask.h"
|
||||
#include "MallTask.h"
|
||||
#include "InfrastTask.h"
|
||||
#include "RecruitTask.h"
|
||||
#include "RoguelikeTask.h"
|
||||
#include "CloseDownTask.h"
|
||||
#include "CopilotTask.h"
|
||||
#include "DepotTask.h"
|
||||
#include "FightTask.h"
|
||||
#include "InfrastTask.h"
|
||||
#include "MallTask.h"
|
||||
#include "RecruitTask.h"
|
||||
#include "RoguelikeTask.h"
|
||||
#include "StartUpTask.h"
|
||||
#include "VisitTask.h"
|
||||
#ifdef ASST_DEBUG
|
||||
#include "DebugTask.h"
|
||||
#endif
|
||||
|
||||
using namespace asst;
|
||||
|
||||
Assistant::Assistant(AsstApiCallback callback, void* callback_arg)
|
||||
: m_callback(callback),
|
||||
m_callback_arg(callback_arg)
|
||||
Assistant::Assistant(AsstApiCallback callback, void* callback_arg) : m_callback(callback), m_callback_arg(callback_arg)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -84,25 +82,29 @@ asst::Assistant::TaskId asst::Assistant::append_task(const std::string& type, co
|
||||
|
||||
std::shared_ptr<PackageTask> ptr = nullptr;
|
||||
|
||||
#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)); }
|
||||
#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 constexpr (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(CloseDownTask)
|
||||
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)
|
||||
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(DepotTask)
|
||||
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(StartUpTask)
|
||||
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(CloseDownTask)
|
||||
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)
|
||||
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(DepotTask)
|
||||
#ifdef ASST_DEBUG
|
||||
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(DebugTask)
|
||||
ASST_ASSISTANT_APPEND_TASK_FROM_STRING_IF_BRANCH(DebugTask)
|
||||
#endif
|
||||
else {
|
||||
else
|
||||
{
|
||||
Log.error(__FUNCTION__, "| invalid type:", type);
|
||||
return 0;
|
||||
}
|
||||
@@ -227,7 +229,7 @@ void Assistant::working_proc()
|
||||
|
||||
std::vector<TaskId> finished_tasks;
|
||||
while (!m_thread_exit) {
|
||||
//LogTraceScope("Assistant::working_proc Loop");
|
||||
// LogTraceScope("Assistant::working_proc Loop");
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (!m_thread_idle && !m_tasks_list.empty()) {
|
||||
@@ -235,15 +237,10 @@ void Assistant::working_proc()
|
||||
lock.unlock();
|
||||
// only one instance of working_proc running, unlock here to allow set_task_param to the running task
|
||||
|
||||
json::value callback_json = json::object{
|
||||
{ "taskchain", task_ptr->get_task_chain() },
|
||||
{ "taskid", id }
|
||||
};
|
||||
json::value callback_json = json::object { { "taskchain", task_ptr->get_task_chain() }, { "taskid", id } };
|
||||
task_callback(AsstMsg::TaskChainStart, callback_json, this);
|
||||
|
||||
task_ptr->set_exit_flag(&m_thread_idle)
|
||||
.set_ctrler(m_ctrler)
|
||||
.set_status(m_status);
|
||||
task_ptr->set_exit_flag(&m_thread_idle).set_ctrler(m_ctrler).set_status(m_status);
|
||||
|
||||
bool ret = task_ptr->run();
|
||||
finished_tasks.emplace_back(id);
|
||||
@@ -264,8 +261,7 @@ void Assistant::working_proc()
|
||||
|
||||
auto delay = Resrc.cfg().get_options().task_delay;
|
||||
lock.lock();
|
||||
m_condvar.wait_for(lock, std::chrono::milliseconds(delay),
|
||||
[&]() -> bool { return m_thread_idle; });
|
||||
m_condvar.wait_for(lock, std::chrono::milliseconds(delay), [&]() -> bool { return m_thread_idle; });
|
||||
}
|
||||
else {
|
||||
m_thread_idle = true;
|
||||
@@ -281,7 +277,7 @@ void Assistant::msg_proc()
|
||||
LogTraceFunction;
|
||||
|
||||
while (!m_thread_exit) {
|
||||
//LogTraceScope("Assistant::msg_proc Loop");
|
||||
// LogTraceScope("Assistant::msg_proc Loop");
|
||||
std::unique_lock<std::mutex> lock(m_msg_mutex);
|
||||
if (!m_msg_queue.empty()) {
|
||||
// 结构化绑定只能是引用,后续的pop会使引用失效,所以需要重新构造一份,这里采用了move的方式
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
||||
#include "AsstTypes.h"
|
||||
#include "AsstMsg.h"
|
||||
#include "AsstTypes.h"
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "NoWarningCVMat.h"
|
||||
|
||||
@@ -10,18 +10,18 @@
|
||||
|
||||
namespace asst
|
||||
{
|
||||
enum class BattleSkillUsage // 干员技能使用方法
|
||||
enum class BattleSkillUsage // 干员技能使用方法
|
||||
{
|
||||
NotUse = 0, // 不自动使用
|
||||
Possibly = 1, // 有就用,例如干员 棘刺 3 技能
|
||||
Once = 2, // 只用一次,例如干员 山 2 技能
|
||||
InTime = 3, // 自动判断使用时机,画饼.jpg
|
||||
NotUse = 0, // 不自动使用
|
||||
Possibly = 1, // 有就用,例如干员 棘刺 3 技能
|
||||
Once = 2, // 只用一次,例如干员 山 2 技能
|
||||
InTime = 3, // 自动判断使用时机,画饼.jpg
|
||||
OnceUsed
|
||||
};
|
||||
struct BattleDeployOper // 干员
|
||||
struct BattleDeployOper // 干员
|
||||
{
|
||||
std::string name;
|
||||
int skill = 1; // 技能序号,取值范围 [1, 3]
|
||||
int skill = 1; // 技能序号,取值范围 [1, 3]
|
||||
BattleSkillUsage skill_usage = BattleSkillUsage::NotUse;
|
||||
};
|
||||
struct BattleDeployInfo
|
||||
@@ -37,28 +37,28 @@ namespace asst
|
||||
Down = 1,
|
||||
Left = 2,
|
||||
Up = 3,
|
||||
None = 4 // 没有方向,通常是无人机之类的
|
||||
None = 4 // 没有方向,通常是无人机之类的
|
||||
};
|
||||
|
||||
enum class BattleActionType // 操作类型
|
||||
enum class BattleActionType // 操作类型
|
||||
{
|
||||
Deploy, // 部署干员
|
||||
UseSkill, // 开技能
|
||||
Retreat, // 撤退干员
|
||||
SkillUsage, // 技能用法
|
||||
SwitchSpeed, // 切换二倍速
|
||||
BulletTime, // 使用 1/5 的速度(点击任意干员),会在下一个任意操作后恢复原速度
|
||||
UseAllSkill, // 使用所有技能,仅肉鸽模式
|
||||
Output, // 仅输出,什么都不操作,界面上也不显示
|
||||
SkillDaemon, // 什么都不做,有技能开技能,直到战斗结束
|
||||
Deploy, // 部署干员
|
||||
UseSkill, // 开技能
|
||||
Retreat, // 撤退干员
|
||||
SkillUsage, // 技能用法
|
||||
SwitchSpeed, // 切换二倍速
|
||||
BulletTime, // 使用 1/5 的速度(点击任意干员),会在下一个任意操作后恢复原速度
|
||||
UseAllSkill, // 使用所有技能,仅肉鸽模式
|
||||
Output, // 仅输出,什么都不操作,界面上也不显示
|
||||
SkillDaemon, // 什么都不做,有技能开技能,直到战斗结束
|
||||
};
|
||||
|
||||
struct BattleAction // 操作
|
||||
struct BattleAction // 操作
|
||||
{
|
||||
int kills = 0;
|
||||
int cost_changes = 0;
|
||||
BattleActionType type = BattleActionType::Deploy;
|
||||
std::string group_name; // 目标名,若 type >= SwitchSpeed, group_name 为空
|
||||
std::string group_name; // 目标名,若 type >= SwitchSpeed, group_name 为空
|
||||
Point location;
|
||||
BattleDeployDirection direction = BattleDeployDirection::Right;
|
||||
BattleSkillUsage modify_usage = BattleSkillUsage::NotUse;
|
||||
@@ -130,4 +130,4 @@ namespace asst
|
||||
};
|
||||
|
||||
using BattleAttackRange = std::vector<Point>;
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include "Assistant.h"
|
||||
#include "AsstTypes.h"
|
||||
#include "Version.h"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
#include "Version.h"
|
||||
|
||||
static constexpr unsigned long long NullSize = static_cast<unsigned long long>(-1);
|
||||
|
||||
|
||||
@@ -18,25 +18,22 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_START \
|
||||
ASST_DO_PRAGMA(warning(push)) \
|
||||
ASST_DO_PRAGMA(warning(disable: 5054))
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_END \
|
||||
ASST_DO_PRAGMA(warning(pop))
|
||||
ASST_DO_PRAGMA(warning(push)) \
|
||||
ASST_DO_PRAGMA(warning(disable : 5054))
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_END ASST_DO_PRAGMA(warning(pop))
|
||||
#elif defined(__clang__)
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_START \
|
||||
ASST_DO_PRAGMA(clang diagnostic push) \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-enum-enum-conversion") \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-anon-enum-enum-conversion") \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wc11-extensions") \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wunused-but-set-variable")
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_END \
|
||||
ASST_DO_PRAGMA(clang diagnostic pop)
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_START \
|
||||
ASST_DO_PRAGMA(clang diagnostic push) \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-enum-enum-conversion") \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-anon-enum-enum-conversion") \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wc11-extensions") \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wunused-but-set-variable")
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_END ASST_DO_PRAGMA(clang diagnostic pop)
|
||||
#elif defined(__GNUC__)
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_START \
|
||||
ASST_DO_PRAGMA(GCC diagnostic push) \
|
||||
ASST_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion")
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_END \
|
||||
ASST_DO_PRAGMA(GCC diagnostic pop)
|
||||
ASST_DO_PRAGMA(GCC diagnostic push) \
|
||||
ASST_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion")
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_END ASST_DO_PRAGMA(GCC diagnostic pop)
|
||||
#else
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_START
|
||||
#define ASST_SUPPRESS_CV_WARNINGS_END
|
||||
@@ -44,16 +41,14 @@ ASST_DO_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_START \
|
||||
ASST_DO_PRAGMA(GCC diagnostic push) \
|
||||
ASST_DO_PRAGMA(GCC diagnostic ignored "-Wmissing-field-initializers")
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_END \
|
||||
ASST_DO_PRAGMA(GCC diagnostic pop)
|
||||
ASST_DO_PRAGMA(GCC diagnostic push) \
|
||||
ASST_DO_PRAGMA(GCC diagnostic ignored "-Wmissing-field-initializers")
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_END ASST_DO_PRAGMA(GCC diagnostic pop)
|
||||
#elif defined(__clang__)
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_START \
|
||||
ASST_DO_PRAGMA(clang diagnostic push) \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wmissing-field-initializers")
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_END \
|
||||
ASST_DO_PRAGMA(clang diagnostic pop)
|
||||
ASST_DO_PRAGMA(clang diagnostic push) \
|
||||
ASST_DO_PRAGMA(clang diagnostic ignored "-Wmissing-field-initializers")
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_END ASST_DO_PRAGMA(clang diagnostic pop)
|
||||
#else
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_START
|
||||
#define ASST_AUTO_DEDUCED_ZERO_INIT_END
|
||||
|
||||
@@ -16,37 +16,36 @@ namespace asst::infrast
|
||||
enum class SmileyType
|
||||
{
|
||||
Invalid = -1,
|
||||
Rest, // 休息完成,绿色笑脸
|
||||
Work, // 工作中,黄色笑脸
|
||||
Distract // 注意力涣散,红色哭脸
|
||||
Rest, // 休息完成,绿色笑脸
|
||||
Work, // 工作中,黄色笑脸
|
||||
Distract // 注意力涣散,红色哭脸
|
||||
};
|
||||
struct Smiley
|
||||
{
|
||||
SmileyType type = SmileyType::Invalid;
|
||||
Rect rect;
|
||||
};
|
||||
enum class Doing // 正在做什么
|
||||
enum class Doing // 正在做什么
|
||||
{
|
||||
Invalid = -1,
|
||||
Nothing, // 什么都不在做,也不在休息也不在工作
|
||||
Resting, // 休息中
|
||||
Working // 工作中
|
||||
Nothing, // 什么都不在做,也不在休息也不在工作
|
||||
Resting, // 休息中
|
||||
Working // 工作中
|
||||
};
|
||||
|
||||
struct Skill
|
||||
{
|
||||
std::string id;
|
||||
std::string templ_name;
|
||||
std::vector<std::string> names; // 很多基建技能是一样的,就是名字不同。所以一个技能id可能对应多个名字
|
||||
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; // 最多选几个该技能
|
||||
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; }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,11 +65,11 @@ namespace asst::infrast
|
||||
{
|
||||
struct Oper
|
||||
{
|
||||
std::string face_hash; // 有些干员的技能是完全一样的,做个hash区分一下不同干员
|
||||
std::string face_hash; // 有些干员的技能是完全一样的,做个hash区分一下不同干员
|
||||
Smiley smiley;
|
||||
double mood_ratio = 0; // 心情进度条的百分比
|
||||
double mood_ratio = 0; // 心情进度条的百分比
|
||||
Doing doing = Doing::Invalid;
|
||||
bool selected = false; // 干员是否已被选择(蓝色的选择框)
|
||||
bool selected = false; // 干员是否已被选择(蓝色的选择框)
|
||||
std::unordered_set<Skill> skills;
|
||||
Rect rect;
|
||||
// 因为OCR识别名字比较费时间,所以仅在name_filter不为空(有识别名字需求)的时候才识别,否则仅保存图片但不识别
|
||||
@@ -93,10 +92,7 @@ namespace asst::infrast
|
||||
}
|
||||
}
|
||||
}
|
||||
bool operator==(const SkillsComb& rhs) const
|
||||
{
|
||||
return skills == rhs.skills;
|
||||
}
|
||||
bool operator==(const SkillsComb& rhs) const { return skills == rhs.skills; }
|
||||
|
||||
std::string desc;
|
||||
std::unordered_set<Skill> skills;
|
||||
@@ -110,18 +106,24 @@ namespace asst::infrast
|
||||
// 基建技能组
|
||||
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个的时候,是否允许补充外部干员
|
||||
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 // 偏激换班模式:会对每一个设施进行换班,计算全局的单设施内最优解,为追求更高效率,会将其他设施内的干员也替换过来;即按技能排序,计算所有拥有该设施技能的干员效率,无论他在不在其他地方工作
|
||||
Gentle, // 温和换班模式:
|
||||
// 会对干员人数不满的设施进行换班,计算单设施内最优解,尽量不破坏原有的干员组合;
|
||||
// 即若设施内干员是满的,则不对该设施进行换班
|
||||
Aggressive, // 激进换班模式:
|
||||
// 会对每一个设施进行换班,计算单设施内最优解,但不会将其他设施中的干员替换过来;
|
||||
// 即按工作状态排序,仅选择前面的干员
|
||||
Extreme // 偏激换班模式:
|
||||
// 会对每一个设施进行换班,计算全局的单设施内最优解,为追求更高效率,会将其他设施内的干员也替换过来;
|
||||
// 即按技能排序,计算所有拥有该设施技能的干员效率,无论他在不在其他地方工作
|
||||
};
|
||||
}
|
||||
} // namespace asst::infrast
|
||||
|
||||
@@ -11,20 +11,20 @@ namespace asst
|
||||
enum class AsstMsg
|
||||
{
|
||||
/* Global Info */
|
||||
InternalError = 0, // 内部错误
|
||||
InitFailed, // 初始化失败
|
||||
ConnectionInfo, // 连接相关错误
|
||||
AllTasksCompleted, // 全部任务完成
|
||||
InternalError = 0, // 内部错误
|
||||
InitFailed, // 初始化失败
|
||||
ConnectionInfo, // 连接相关错误
|
||||
AllTasksCompleted, // 全部任务完成
|
||||
/* TaskChain Info */
|
||||
TaskChainError = 10000, // 任务链执行/识别错误
|
||||
TaskChainStart, // 任务链开始
|
||||
TaskChainCompleted, // 任务链完成
|
||||
TaskChainExtraInfo, // 任务链额外信息
|
||||
TaskChainError = 10000, // 任务链执行/识别错误
|
||||
TaskChainStart, // 任务链开始
|
||||
TaskChainCompleted, // 任务链完成
|
||||
TaskChainExtraInfo, // 任务链额外信息
|
||||
/* SubTask Info */
|
||||
SubTaskError = 20000, // 原子任务执行/识别错误
|
||||
SubTaskStart, // 原子任务开始
|
||||
SubTaskCompleted, // 原子任务完成
|
||||
SubTaskExtraInfo // 原子任务额外信息
|
||||
SubTaskError = 20000, // 原子任务执行/识别错误
|
||||
SubTaskStart, // 原子任务开始
|
||||
SubTaskCompleted, // 原子任务完成
|
||||
SubTaskExtraInfo // 原子任务额外信息
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const AsstMsg& type)
|
||||
@@ -56,5 +56,5 @@ namespace asst
|
||||
// void* 外部调用者自定义参数,每次回调会带出去,建议传个(void*)this指针进来
|
||||
using AsstCallback = std::function<void(AsstMsg, const json::value&, void*)>;
|
||||
|
||||
using AsstApiCallback = void(*)(int msg, const char* detail_json, void* custom_arg);
|
||||
using AsstApiCallback = void (*)(int msg, const char* detail_json, void* custom_arg);
|
||||
}
|
||||
|
||||
@@ -16,21 +16,20 @@ namespace asst
|
||||
struct remove_if_fn
|
||||
{
|
||||
template <permutable I, sentinel_for<I> S, typename C, typename P = identity>
|
||||
constexpr subrange<I>
|
||||
operator()(I first, S last, C pred, P proj = P{}) const
|
||||
constexpr subrange<I> operator()(I first, S last, C pred, P proj = P {}) const
|
||||
{
|
||||
return { ::ranges::remove_if(std::move(first), last, std::move(pred), std::move(proj)), last };
|
||||
}
|
||||
|
||||
template <forward_range Rng, typename C, typename P = identity>
|
||||
constexpr borrowed_subrange_t<Rng> operator()(Rng&& rng, C pred, P proj = P{}) const
|
||||
constexpr borrowed_subrange_t<Rng> operator()(Rng&& rng, C pred, P proj = P {}) const
|
||||
{
|
||||
return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj));
|
||||
}
|
||||
};
|
||||
|
||||
// this one will be found before ::ranges::remove_if
|
||||
inline constexpr remove_if_fn remove_if{};
|
||||
inline constexpr remove_if_fn remove_if {};
|
||||
}
|
||||
|
||||
namespace views = ::ranges::views;
|
||||
@@ -50,8 +49,8 @@ namespace asst
|
||||
|
||||
#error "Not implemented"
|
||||
|
||||
#include <boost/range/algorithm.hpp>
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <boost/range/algorithm.hpp>
|
||||
|
||||
namespace asst
|
||||
{
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
@@ -38,10 +38,7 @@ namespace asst
|
||||
Point& operator=(Point&&) noexcept = default;
|
||||
Point operator-() const noexcept { return { -x, -y }; }
|
||||
bool operator==(const Point& rhs) const noexcept { return x == rhs.x && y == rhs.y; }
|
||||
std::string to_string() const
|
||||
{
|
||||
return "[ " + std::to_string(x) + ", " + std::to_string(y) + " ]";
|
||||
}
|
||||
std::string to_string() const { return "[ " + std::to_string(x) + ", " + std::to_string(y) + " ]"; }
|
||||
static constexpr Point right() { return { 1, 0 }; }
|
||||
static constexpr Point down() { return { 0, 1 }; }
|
||||
static constexpr Point left() { return { -1, 0 }; }
|
||||
@@ -49,24 +46,44 @@ namespace asst
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
#define DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN(Op) \
|
||||
friend Point operator Op (const Point& lhs, const Point& rhs) noexcept { return {lhs.x Op rhs.x, lhs.y Op rhs.y}; } \
|
||||
friend Point& operator Op##= (Point& val, const Point& opd) noexcept { val.x Op##= opd.x; val.y Op##= opd.y; return val; }
|
||||
#define DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN(Op) \
|
||||
friend Point operator Op(const Point& lhs, const Point& rhs) noexcept \
|
||||
{ \
|
||||
return { lhs.x Op rhs.x, lhs.y Op rhs.y }; \
|
||||
} \
|
||||
friend Point& operator Op##=(Point& val, const Point& opd) noexcept \
|
||||
{ \
|
||||
val.x Op## = opd.x; \
|
||||
val.y Op## = opd.y; \
|
||||
return val; \
|
||||
}
|
||||
|
||||
DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN(+)
|
||||
DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN(-)
|
||||
DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN(*)
|
||||
DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN(-)
|
||||
DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN(*)
|
||||
|
||||
#undef DEFINE_ASST_POINT_BINARY_OP_AND_ARG_ASSIGN
|
||||
|
||||
friend Point operator*(int scalar, const Point& value) noexcept { return { value.x * scalar, value.y * scalar }; }
|
||||
friend Point operator*(const Point& value, int scalar) noexcept { return { value.x * scalar, value.y * scalar }; }
|
||||
static int dot(const Point& lhs, const Point& rhs) noexcept { return (lhs.x * rhs.x) + (lhs.y * rhs.y); }
|
||||
friend Point operator*(int scalar, const Point& value) noexcept
|
||||
{
|
||||
return { value.x * scalar, value.y * scalar };
|
||||
}
|
||||
friend Point operator*(const Point& value, int scalar) noexcept
|
||||
{
|
||||
return { value.x * scalar, value.y * scalar };
|
||||
}
|
||||
static int dot(const Point& lhs, const Point& rhs) noexcept
|
||||
{
|
||||
return (lhs.x * rhs.x) + (lhs.y * rhs.y);
|
||||
}
|
||||
static double distance(const Point& lhs, const Point& rhs) noexcept
|
||||
{
|
||||
return std::sqrt(std::pow(rhs.x - lhs.x, 2) + std::pow(rhs.y - lhs.y, 2));
|
||||
}
|
||||
double length() const noexcept { return std::sqrt(static_cast<double>(dot(*this, *this))); }
|
||||
double length() const noexcept
|
||||
{
|
||||
return std::sqrt(static_cast<double>(dot(*this, *this)));
|
||||
}
|
||||
};
|
||||
|
||||
struct Rect
|
||||
@@ -75,23 +92,18 @@ friend Point& operator Op##= (Point& val, const Point& opd) noexcept { val.x Op#
|
||||
~Rect() = default;
|
||||
Rect(const Rect&) noexcept = default;
|
||||
Rect(Rect&&) noexcept = default;
|
||||
Rect(int x, int y, int width, int height)
|
||||
: x(x), y(y), width(width), height(height)
|
||||
{}
|
||||
Rect(int x, int y, int width, int height) : x(x), y(y), width(width), height(height) {}
|
||||
Rect operator*(double rhs) const
|
||||
{
|
||||
return { x, y, static_cast<int>(width * rhs), static_cast<int>(height * rhs) };
|
||||
}
|
||||
int area() const noexcept
|
||||
{
|
||||
return width * height;
|
||||
}
|
||||
int area() const noexcept { return width * height; }
|
||||
Rect center_zoom(double scale, int max_width = INT_MAX, int max_height = INT_MAX) const
|
||||
{
|
||||
const int half_width_scale = static_cast<int>(width * (1 - scale) / 2);
|
||||
const int half_height_scale = static_cast<int>(height * (1 - scale) / 2);
|
||||
Rect dst(x + half_width_scale, y + half_height_scale,
|
||||
static_cast<int>(width * scale), static_cast<int>(height * scale));
|
||||
Rect dst(x + half_width_scale, y + half_height_scale, static_cast<int>(width * scale),
|
||||
static_cast<int>(height * scale));
|
||||
if (dst.x < 0) {
|
||||
dst.x = 0;
|
||||
}
|
||||
@@ -115,7 +127,8 @@ friend Point& operator Op##= (Point& val, const Point& opd) noexcept { val.x Op#
|
||||
}
|
||||
bool include(const Rect& rhs) const noexcept
|
||||
{
|
||||
return x <= rhs.x && y <= rhs.y && (x + width) >= (rhs.x + rhs.width) && (y + height) >= (rhs.y + rhs.height);
|
||||
return x <= rhs.x && y <= rhs.y && (x + width) >= (rhs.x + rhs.width) &&
|
||||
(y + height) >= (rhs.y + rhs.height);
|
||||
}
|
||||
bool include(const Point& rhs) const noexcept
|
||||
{
|
||||
@@ -123,12 +136,10 @@ friend Point& operator Op##= (Point& val, const Point& opd) noexcept { val.x Op#
|
||||
}
|
||||
std::string to_string() const
|
||||
{
|
||||
return "[ " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(width) + ", " + std::to_string(height) + " ]";
|
||||
}
|
||||
Rect move(Rect move) const
|
||||
{
|
||||
return { x + move.x, y + move.y, move.width, move.height };
|
||||
return "[ " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(width) + ", " +
|
||||
std::to_string(height) + " ]";
|
||||
}
|
||||
Rect move(Rect move) const { return { x + move.x, y + move.y, move.width, move.height }; }
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
@@ -142,26 +153,15 @@ friend Point& operator Op##= (Point& val, const Point& opd) noexcept { val.x Op#
|
||||
~TextRect() = default;
|
||||
TextRect(const TextRect&) = default;
|
||||
TextRect(TextRect&&) noexcept = default;
|
||||
TextRect(double score, const Rect& rect, const std::string& text)
|
||||
: score(score), rect(rect), text(text)
|
||||
{}
|
||||
TextRect(double score, const Rect& rect, const std::string& text) : score(score), rect(rect), text(text) {}
|
||||
|
||||
explicit operator std::string() const noexcept { return text; }
|
||||
explicit operator Rect() const noexcept { return rect; }
|
||||
std::string to_string() const
|
||||
{
|
||||
return text + " : " + rect.to_string() + ", score: " + std::to_string(score);
|
||||
}
|
||||
std::string to_string() const { return text + " : " + rect.to_string() + ", score: " + std::to_string(score); }
|
||||
TextRect& operator=(const TextRect&) = default;
|
||||
TextRect& operator=(TextRect&&) noexcept = default;
|
||||
bool operator==(const TextRect& rhs) const noexcept
|
||||
{
|
||||
return text == rhs.text && rect == rhs.rect;
|
||||
}
|
||||
bool operator==(const std::string& rhs) const noexcept
|
||||
{
|
||||
return text == rhs;
|
||||
}
|
||||
bool operator==(const TextRect& rhs) const noexcept { return text == rhs.text && rect == rhs.rect; }
|
||||
bool operator==(const std::string& rhs) const noexcept { return text == rhs; }
|
||||
|
||||
double score = 0.0;
|
||||
Rect rect;
|
||||
@@ -184,9 +184,7 @@ friend Point& operator Op##= (Point& val, const Point& opd) noexcept { val.x Op#
|
||||
~MatchRect() = default;
|
||||
MatchRect(const MatchRect&) = default;
|
||||
MatchRect(MatchRect&&) noexcept = default;
|
||||
MatchRect(double score, const Rect& rect)
|
||||
: score(score), rect(rect)
|
||||
{}
|
||||
MatchRect(double score, const Rect& rect) : score(score), rect(rect) {}
|
||||
|
||||
explicit operator Rect() const noexcept { return rect; }
|
||||
MatchRect& operator=(const MatchRect&) = default;
|
||||
@@ -195,7 +193,7 @@ friend Point& operator Op##= (Point& val, const Point& opd) noexcept { val.x Op#
|
||||
double score = 0.0;
|
||||
Rect rect;
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
namespace std
|
||||
{
|
||||
@@ -213,7 +211,8 @@ namespace std
|
||||
{
|
||||
size_t operator()(const asst::Rect& rect) const noexcept
|
||||
{
|
||||
return std::hash<int>()(rect.x) ^ std::hash<int>()(rect.y) ^ std::hash<int>()(rect.width) ^ std::hash<int>()(rect.height);
|
||||
return std::hash<int>()(rect.x) ^ std::hash<int>()(rect.y) ^ std::hash<int>()(rect.width) ^
|
||||
std::hash<int>()(rect.height);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
@@ -238,10 +237,10 @@ namespace asst
|
||||
DoNothing = 0x200, // 什么都不做
|
||||
Stop = 0x400, // 停止当前Task
|
||||
BasicSwipe = 0x1000,
|
||||
SwipeToTheLeft = BasicSwipe | 1, // 往左划一下
|
||||
SwipeToTheRight = BasicSwipe | 2, // 往右划一下
|
||||
SlowlySwipeToTheLeft = SwipeToTheLeft | 4, // 慢慢的往左划一下
|
||||
SlowlySwipeToTheRight = SwipeToTheRight | 8 // 慢慢的往右划一下
|
||||
SwipeToTheLeft = BasicSwipe | 1, // 往左划一下
|
||||
SwipeToTheRight = BasicSwipe | 2, // 往右划一下
|
||||
SlowlySwipeToTheLeft = SwipeToTheLeft | 4, // 慢慢的往左划一下
|
||||
SlowlySwipeToTheRight = SwipeToTheRight | 8 // 慢慢的往右划一下
|
||||
};
|
||||
|
||||
// 任务信息
|
||||
@@ -253,25 +252,28 @@ namespace asst
|
||||
TaskInfo(TaskInfo&&) noexcept = default;
|
||||
TaskInfo& operator=(const TaskInfo&) = default;
|
||||
TaskInfo& operator=(TaskInfo&&) noexcept = default;
|
||||
std::string name; // 任务名
|
||||
AlgorithmType algorithm = // 图像算法类型
|
||||
std::string name; // 任务名
|
||||
AlgorithmType algorithm = // 图像算法类型
|
||||
AlgorithmType::Invalid;
|
||||
ProcessTaskAction action = // 要进行的操作
|
||||
ProcessTaskAction::Invalid;
|
||||
std::vector<std::string> sub; // 子任务(列表)
|
||||
bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务
|
||||
std::vector<std::string> next; // 下一个可能的任务(列表)
|
||||
int max_times = INT_MAX; // 任务最多执行多少次
|
||||
std::vector<std::string> exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
|
||||
std::vector<std::string> on_error_next; // 任务出错之后要去执行什么
|
||||
std::vector<std::string> reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1
|
||||
Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域
|
||||
int pre_delay = 0; // 执行该任务前的延时
|
||||
int rear_delay = 0; // 执行该任务后的延时
|
||||
int retry_times = INT_MAX; // 未找到图像时的重试次数
|
||||
Rect roi; // 要识别的区域,若为0则全图识别
|
||||
Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。即识别到了res,点击res + result_move的位置
|
||||
bool cache = false; // 是否使用缓存区域
|
||||
std::vector<std::string> sub; // 子任务(列表)
|
||||
bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务
|
||||
std::vector<std::string> next; // 下一个可能的任务(列表)
|
||||
int max_times = INT_MAX; // 任务最多执行多少次
|
||||
std::vector<std::string> exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
|
||||
std::vector<std::string> on_error_next; // 任务出错之后要去执行什么
|
||||
std::vector<std::string> reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。
|
||||
// 例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,
|
||||
// 所以蓝色开始行动要-1
|
||||
Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域
|
||||
int pre_delay = 0; // 执行该任务前的延时
|
||||
int rear_delay = 0; // 执行该任务后的延时
|
||||
int retry_times = INT_MAX; // 未找到图像时的重试次数
|
||||
Rect roi; // 要识别的区域,若为0则全图识别
|
||||
Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。
|
||||
// 即识别到了res,点击res + result_move的位置
|
||||
bool cache = false; // 是否使用缓存区域
|
||||
};
|
||||
|
||||
// 文字识别任务的信息
|
||||
@@ -284,9 +286,9 @@ namespace asst
|
||||
OcrTaskInfo& operator=(const OcrTaskInfo&) = default;
|
||||
OcrTaskInfo& operator=(OcrTaskInfo&&) noexcept = default;
|
||||
std::vector<std::string> text; // 文字的容器,匹配到这里面任一个,就算匹配上了
|
||||
bool full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
|
||||
bool full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
|
||||
std::unordered_map<std::string, std::string>
|
||||
replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配
|
||||
replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配
|
||||
};
|
||||
|
||||
// 图片匹配任务的信息
|
||||
@@ -313,9 +315,9 @@ namespace asst
|
||||
HashTaskInfo(HashTaskInfo&&) noexcept = default;
|
||||
HashTaskInfo& operator=(const HashTaskInfo&) = default;
|
||||
HashTaskInfo& operator=(HashTaskInfo&&) noexcept = default;
|
||||
std::vector<std::string> hashes; // 需要多个哈希值
|
||||
int dist_threshold = 0; // 汉明距离阈值
|
||||
std::pair<int, int> mask_range; // 掩码的二值化范围
|
||||
bool bound = false; // 是否裁剪周围黑边
|
||||
std::vector<std::string> hashes; // 需要多个哈希值
|
||||
int dist_threshold = 0; // 汉明距离阈值
|
||||
std::pair<int, int> mask_range; // 掩码的二值化范围
|
||||
bool bound = false; // 是否裁剪周围黑边
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -10,22 +10,24 @@
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <ctime>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <memory.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace asst::utils
|
||||
{
|
||||
// delete instantiation of template with message, when static_assert(false, Message) does not work
|
||||
#define ASST_STATIC_ASSERT_FALSE(Message, ...) \
|
||||
// delete instantiation of template with message, when static_assert(false, Message) does not work
|
||||
#define ASST_STATIC_ASSERT_FALSE(Message, ...) \
|
||||
static_assert(::asst::utils::integral_constant_at_template_instantiation<bool, false, __VA_ARGS__>::value, Message)
|
||||
template <typename T, T Val, typename... Unused>
|
||||
struct integral_constant_at_template_instantiation : std::integral_constant<T, Val> {};
|
||||
struct integral_constant_at_template_instantiation : std::integral_constant<T, Val>
|
||||
{};
|
||||
|
||||
inline void _string_replace_all(std::string& str, const std::string_view& old_value, const std::string_view& new_value)
|
||||
inline void _string_replace_all(std::string& str, const std::string_view& old_value,
|
||||
const std::string_view& new_value)
|
||||
{
|
||||
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)
|
||||
@@ -35,14 +37,16 @@ namespace asst::utils
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string string_replace_all(const std::string& src, const std::string_view& old_value, const std::string_view& new_value)
|
||||
inline std::string string_replace_all(const std::string& src, const std::string_view& old_value,
|
||||
const std::string_view& new_value)
|
||||
{
|
||||
std::string str = src;
|
||||
_string_replace_all(str, old_value, new_value);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline std::string string_replace_all_batch(const std::string& src, std::initializer_list<std::pair<std::string_view, std::string_view>>&& replace_pairs)
|
||||
inline std::string string_replace_all_batch(
|
||||
const std::string& src, std::initializer_list<std::pair<std::string_view, std::string_view>>&& replace_pairs)
|
||||
{
|
||||
std::string str = src;
|
||||
for (const auto& [old_value, new_value] : replace_pairs) {
|
||||
@@ -51,10 +55,10 @@ namespace asst::utils
|
||||
return str;
|
||||
}
|
||||
|
||||
template<typename map_t>
|
||||
inline std::string string_replace_all_batch(const std::string& src, const map_t& replace_pairs)
|
||||
requires std::derived_from<typename map_t::value_type::first_type, std::string>
|
||||
&& std::derived_from<typename map_t::value_type::second_type, std::string>
|
||||
template <typename map_t>
|
||||
inline std::string string_replace_all_batch(const std::string& src, const map_t& replace_pairs) requires
|
||||
std::derived_from<typename map_t::value_type::first_type, std::string> &&
|
||||
std::derived_from<typename map_t::value_type::second_type, std::string>
|
||||
{
|
||||
std::string str = src;
|
||||
for (const auto& [old_value, new_value] : replace_pairs) {
|
||||
@@ -75,8 +79,7 @@ namespace asst::utils
|
||||
pos1 = pos2 + delimiter.size();
|
||||
pos2 = str.find(delimiter, pos1);
|
||||
}
|
||||
if (pos1 != str.length())
|
||||
result.emplace_back(str.substr(pos1));
|
||||
if (pos1 != str.length()) result.emplace_back(str.substr(pos1));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -89,25 +92,24 @@ namespace asst::utils
|
||||
GetLocalTime(&curtime);
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buff, sizeof(buff),
|
||||
#else // ! _MSC_VER
|
||||
#else // ! _MSC_VER
|
||||
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);
|
||||
#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);
|
||||
|
||||
#else // ! _WIN32
|
||||
struct timeval tv {};
|
||||
#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);
|
||||
#endif // END _WIN32
|
||||
#endif // END _WIN32
|
||||
return buff;
|
||||
}
|
||||
|
||||
template<typename _ = void>
|
||||
template <typename _ = void>
|
||||
inline std::string ansi_to_utf8(const std::string& ansi_str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -131,13 +133,13 @@ namespace asst::utils
|
||||
str = nullptr;
|
||||
|
||||
return strTemp;
|
||||
#else // Don't fucking use gbk in linux!
|
||||
#else // Don't fucking use gbk in linux!
|
||||
ASST_STATIC_ASSERT_FALSE("Workaround for windows, not implemented in other OS yet.", _);
|
||||
return ansi_str;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename _ = void>
|
||||
template <typename _ = void>
|
||||
inline std::string utf8_to_ansi(const std::string& utf8_str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -161,13 +163,13 @@ namespace asst::utils
|
||||
sz_ansi = nullptr;
|
||||
|
||||
return strTemp;
|
||||
#else // Don't fucking use gbk in linux!
|
||||
#else // Don't fucking use gbk in linux!
|
||||
ASST_STATIC_ASSERT_FALSE("Workaround for windows, not implemented in other OS yet.", _);
|
||||
return utf8_str;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename _ = void>
|
||||
template <typename _ = void>
|
||||
inline std::string utf8_to_unicode_escape(const std::string& utf8_str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -179,7 +181,7 @@ namespace asst::utils
|
||||
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wstr, len);
|
||||
|
||||
std::string unicode_escape_str = {};
|
||||
constexpr static char hexcode[] = "0123456789abcdef";
|
||||
constinit static char hexcode[] = "0123456789abcdef";
|
||||
for (const wchar_t* pchr = wstr; *pchr; ++pchr) {
|
||||
const wchar_t& chr = *pchr;
|
||||
if (chr > 255) {
|
||||
@@ -207,7 +209,7 @@ namespace asst::utils
|
||||
template <typename RetTy, typename ArgType>
|
||||
constexpr inline RetTy make_rect(const ArgType& rect)
|
||||
{
|
||||
return RetTy{ rect.x, rect.y, rect.width, rect.height };
|
||||
return RetTy { rect.x, rect.y, rect.width, rect.height };
|
||||
}
|
||||
|
||||
inline std::string load_file_without_bom(const std::string& filename)
|
||||
@@ -226,7 +228,8 @@ namespace asst::utils
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
@@ -241,9 +244,9 @@ namespace asst::utils
|
||||
|
||||
#ifdef _WIN32
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_START
|
||||
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
|
||||
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_END
|
||||
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
pipe_sec_attr.lpSecurityDescriptor = nullptr;
|
||||
pipe_sec_attr.bInheritHandle = TRUE;
|
||||
HANDLE pipe_read = nullptr;
|
||||
@@ -251,19 +254,20 @@ namespace asst::utils
|
||||
CreatePipe(&pipe_read, &pipe_child_write, &pipe_sec_attr, PipeBuffSize);
|
||||
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_START
|
||||
STARTUPINFOA si = { 0 };
|
||||
STARTUPINFOA si = { 0 };
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_END
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdOutput = pipe_child_write;
|
||||
si.hStdError = pipe_child_write;
|
||||
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_START
|
||||
PROCESS_INFORMATION pi = { nullptr };
|
||||
PROCESS_INFORMATION pi = { nullptr };
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_END
|
||||
|
||||
BOOL p_ret = CreateProcessA(nullptr, const_cast<LPSTR>(cmdline.c_str()), nullptr, nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi);
|
||||
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;
|
||||
@@ -291,7 +295,9 @@ namespace asst::utils
|
||||
int pipe_out[2] = { 0 };
|
||||
int pipe_in_ret = pipe(pipe_in);
|
||||
int pipe_out_ret = pipe(pipe_out);
|
||||
if (pipe_in_ret != 0 || pipe_out_ret != 0) { return {}; }
|
||||
if (pipe_in_ret != 0 || pipe_out_ret != 0) {
|
||||
return {};
|
||||
}
|
||||
fcntl(pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
|
||||
int exit_ret = 0;
|
||||
int child = fork();
|
||||
@@ -339,4 +345,4 @@ namespace asst::utils
|
||||
#endif
|
||||
return pipe_str;
|
||||
}
|
||||
}
|
||||
} // namespace asst::utils
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
#include "AutoRecruitTask.h"
|
||||
|
||||
#include "Resource.h"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "MultiMatchImageAnalyzer.h"
|
||||
#include "Controller.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "RecruitImageAnalyzer.h"
|
||||
#include "RecruitConfiger.h"
|
||||
#include "Logger.hpp"
|
||||
#include "MultiMatchImageAnalyzer.h"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "RecruitConfiger.h"
|
||||
#include "RecruitImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
|
||||
#include "AsstRanges.hpp"
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include "AsstRanges.hpp"
|
||||
|
||||
namespace asst::recruit_calc
|
||||
{
|
||||
// all combinations and their operator list, excluding empty set and 6-star operators while there is no senior tag
|
||||
auto get_all_combs(const std::vector<std::string>& tags, const std::vector<RecruitOperInfo>& all_ops = Resrc.recruit().get_all_opers())
|
||||
auto get_all_combs(const std::vector<std::string>& tags,
|
||||
const std::vector<RecruitOperInfo>& all_ops = Resrc.recruit().get_all_opers())
|
||||
{
|
||||
std::vector<RecruitCombs> rcs_with_single_tag;
|
||||
|
||||
@@ -56,19 +57,25 @@ namespace asst::recruit_calc
|
||||
// select one tag first
|
||||
for (size_t i = 0; i < tag_size; ++i) {
|
||||
RecruitCombs temp1 = rcs_with_single_tag[i];
|
||||
if (temp1.opers.empty()) continue; // this is not possible
|
||||
if (temp1.opers.empty()) [[unlikely]] {
|
||||
continue; // this is not possible
|
||||
}
|
||||
result.emplace_back(temp1); // that is it
|
||||
|
||||
// but what if another tag is also selected
|
||||
for (size_t j = i + 1; j < tag_size; ++j) {
|
||||
RecruitCombs temp2 = temp1 * rcs_with_single_tag[j];
|
||||
if (temp2.opers.empty()) continue;
|
||||
if (temp2.opers.empty()) [[unlikely]] {
|
||||
continue;
|
||||
}
|
||||
result.emplace_back(temp2); // two tags only
|
||||
|
||||
// select a third one
|
||||
for (size_t k = j + 1; k < tag_size; ++k) {
|
||||
RecruitCombs temp3 = temp2 * rcs_with_single_tag[k];
|
||||
if (temp3.opers.empty()) continue;
|
||||
if (temp3.opers.empty()) [[unlikely]] {
|
||||
continue;
|
||||
}
|
||||
result.emplace_back(temp3);
|
||||
}
|
||||
}
|
||||
@@ -99,7 +106,7 @@ namespace asst::recruit_calc
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace asst::recruit_calc
|
||||
|
||||
asst::AutoRecruitTask& asst::AutoRecruitTask::set_select_level(std::vector<int> select_level) noexcept
|
||||
{
|
||||
@@ -194,7 +201,9 @@ bool asst::AutoRecruitTask::_run()
|
||||
|
||||
// m_cur_times means how many times has the confirm button been pressed, NOT expedited plans used
|
||||
while (m_cur_times != m_max_times) {
|
||||
if (m_force_discard_flag) { return false; }
|
||||
if (m_force_discard_flag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto start_rect = try_get_start_button(m_ctrler->get_image());
|
||||
if (start_rect) {
|
||||
@@ -203,8 +212,11 @@ bool asst::AutoRecruitTask::_run()
|
||||
++m_cur_times;
|
||||
else
|
||||
++m_slot_fail;
|
||||
if (m_slot_fail >= slot_retry_limit) { return false; }
|
||||
} else {
|
||||
if (m_slot_fail >= slot_retry_limit) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!check_recruit_home_page()) return false;
|
||||
Log.info("There is no available start button.");
|
||||
if (!m_use_expedited) return true;
|
||||
@@ -215,11 +227,15 @@ bool asst::AutoRecruitTask::_run()
|
||||
Log.info("ready to use expedited plan");
|
||||
if (recruit_now()) {
|
||||
hire_all();
|
||||
} else {
|
||||
// there is a small chance that confirm button were clicked twice and got stuck into the bottom-right slot
|
||||
// ref: issues/1491
|
||||
if (check_recruit_home_page()) { m_force_discard_flag = true; } // ran out of expedited plan?
|
||||
else Log.info("Not in home page after failing to use expedited plan. ");
|
||||
}
|
||||
else {
|
||||
// There is a small chance that confirm button were clicked twice and got stuck into the bottom-right
|
||||
// slot. ref: issues/1491
|
||||
if (check_recruit_home_page()) {
|
||||
m_force_discard_flag = true;
|
||||
} // ran out of expedited plan?
|
||||
else
|
||||
Log.info("Not in home page after failing to use expedited plan.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -240,11 +256,8 @@ std::optional<asst::Rect> asst::AutoRecruitTask::try_get_start_button(const cv::
|
||||
{
|
||||
const auto result = start_recruit_analyze(image);
|
||||
if (result.empty()) return std::nullopt;
|
||||
auto iter =
|
||||
ranges::find_if(result,
|
||||
[&](const TextRect& r) -> bool {
|
||||
return !m_force_skipped.contains(slot_index_from_rect(r.rect));
|
||||
});
|
||||
auto iter = ranges::find_if(
|
||||
result, [&](const TextRect& r) -> bool { return !m_force_skipped.contains(slot_index_from_rect(r.rect)); });
|
||||
if (iter == result.cend()) return std::nullopt;
|
||||
Log.info("Found slot index", slot_index_from_rect(iter->rect), ".");
|
||||
return iter->rect;
|
||||
@@ -350,24 +363,24 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
|
||||
|
||||
// special tags
|
||||
const std::vector<std::string> SpecialTags = { "高级资深干员", "资深干员" };
|
||||
if (auto special_iter = ranges::find_first_of(SpecialTags, tag_names);
|
||||
special_iter != SpecialTags.cend()) [[unlikely]] {
|
||||
has_special_tag = true;
|
||||
json::value cb_info = info;
|
||||
cb_info["what"] = "RecruitSpecialTag";
|
||||
cb_info["details"]["tag"] = *special_iter;
|
||||
callback(AsstMsg::SubTaskExtraInfo, cb_info);
|
||||
if (auto special_iter = ranges::find_first_of(SpecialTags, tag_names); special_iter != SpecialTags.cend())
|
||||
[[unlikely]] {
|
||||
has_special_tag = true;
|
||||
json::value cb_info = info;
|
||||
cb_info["what"] = "RecruitSpecialTag";
|
||||
cb_info["details"]["tag"] = *special_iter;
|
||||
callback(AsstMsg::SubTaskExtraInfo, cb_info);
|
||||
}
|
||||
|
||||
// robot tags
|
||||
const std::vector<std::string> RobotTags = { "支援机械" };
|
||||
if (auto robot_iter = ranges::find_first_of(RobotTags, tag_names);
|
||||
robot_iter != RobotTags.cend()) [[unlikely]] {
|
||||
has_robot_tag = true;
|
||||
json::value cb_info = info;
|
||||
cb_info["what"] = "RecruitSpecialTag";
|
||||
cb_info["details"]["tag"] = *robot_iter;
|
||||
callback(AsstMsg::SubTaskExtraInfo, cb_info);
|
||||
if (auto robot_iter = ranges::find_first_of(RobotTags, tag_names); robot_iter != RobotTags.cend())
|
||||
[[unlikely]] {
|
||||
has_robot_tag = true;
|
||||
json::value cb_info = info;
|
||||
cb_info["what"] = "RecruitSpecialTag";
|
||||
cb_info["details"]["tag"] = *robot_iter;
|
||||
callback(AsstMsg::SubTaskExtraInfo, cb_info);
|
||||
}
|
||||
|
||||
std::vector<RecruitCombs> result_vec = recruit_calc::get_all_combs(tag_names);
|
||||
@@ -379,36 +392,31 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
|
||||
auto sec = ranges::find_if(rc.opers, [](const RecruitOperInfo& op) { return op.level >= 3; });
|
||||
if (sec != rc.opers.end()) {
|
||||
rc.min_level = sec->level;
|
||||
rc.avg_level = std::transform_reduce(
|
||||
sec, rc.opers.end(), 0.,
|
||||
std::plus<double>{},
|
||||
std::mem_fn(&RecruitOperInfo::level)) / static_cast<double>(std::distance(sec, rc.opers.end()));
|
||||
rc.avg_level = std::transform_reduce(sec, rc.opers.end(), 0., std::plus<double> {},
|
||||
std::mem_fn(&RecruitOperInfo::level)) /
|
||||
static_cast<double>(std::distance(sec, rc.opers.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ranges::sort(result_vec,
|
||||
[&](const RecruitCombs& lhs, const RecruitCombs& rhs) -> bool {
|
||||
// prefer the one with special tag
|
||||
// workaround for https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/1336
|
||||
if (has_special_tag) {
|
||||
bool l_has =
|
||||
ranges::find_first_of(lhs.tags, SpecialTags) != lhs.tags.cend();
|
||||
bool r_has =
|
||||
ranges::find_first_of(rhs.tags, SpecialTags) != rhs.tags.cend();
|
||||
if (l_has != r_has) return l_has > r_has;
|
||||
}
|
||||
|
||||
if (lhs.min_level != rhs.min_level)
|
||||
return lhs.min_level > rhs.min_level; // 最小等级大的,排前面
|
||||
else if (lhs.max_level != rhs.max_level)
|
||||
return lhs.max_level > rhs.max_level; // 最大等级大的,排前面
|
||||
else if (std::fabs(lhs.avg_level - rhs.avg_level) > DoubleDiff)
|
||||
return lhs.avg_level > rhs.avg_level; // 平均等级高的,排前面
|
||||
else
|
||||
return lhs.tags.size() < rhs.tags.size(); // Tag数量少的,排前面
|
||||
ranges::sort(result_vec, [&](const RecruitCombs& lhs, const RecruitCombs& rhs) -> bool {
|
||||
// prefer the one with special tag
|
||||
// workaround for https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/1336
|
||||
if (has_special_tag) {
|
||||
bool l_has = ranges::find_first_of(lhs.tags, SpecialTags) != lhs.tags.cend();
|
||||
bool r_has = ranges::find_first_of(rhs.tags, SpecialTags) != rhs.tags.cend();
|
||||
if (l_has != r_has) return l_has > r_has;
|
||||
}
|
||||
);
|
||||
|
||||
if (lhs.min_level != rhs.min_level)
|
||||
return lhs.min_level > rhs.min_level; // 最小等级大的,排前面
|
||||
else if (lhs.max_level != rhs.max_level)
|
||||
return lhs.max_level > rhs.max_level; // 最大等级大的,排前面
|
||||
else if (std::fabs(lhs.avg_level - rhs.avg_level) > DoubleDiff)
|
||||
return lhs.avg_level > rhs.avg_level; // 平均等级高的,排前面
|
||||
else
|
||||
return lhs.tags.size() < rhs.tags.size(); // Tag数量少的,排前面
|
||||
});
|
||||
|
||||
if (result_vec.empty()) continue;
|
||||
|
||||
@@ -451,24 +459,21 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
|
||||
if (!m_dirty_slots.contains(index)) {
|
||||
async_upload_result(info["details"]);
|
||||
m_dirty_slots.emplace(index); // mark as dirty
|
||||
} else Log.info("will not report, dirty slots are", m_dirty_slots);
|
||||
}
|
||||
else
|
||||
Log.info("will not report, dirty slots are", m_dirty_slots);
|
||||
}
|
||||
|
||||
if (need_exit()) return {};
|
||||
|
||||
// refresh
|
||||
if (m_need_refresh && has_refresh
|
||||
&& !has_special_tag
|
||||
&& final_combination.min_level == 3
|
||||
&& !(m_skip_robot && has_robot_tag)
|
||||
) {
|
||||
if (m_need_refresh && has_refresh && !has_special_tag && final_combination.min_level == 3 &&
|
||||
!(m_skip_robot && has_robot_tag)) {
|
||||
if (refresh_count > refresh_limit) [[unlikely]] {
|
||||
json::value cb_info = basic_info();
|
||||
cb_info["what"] = "RecruitError";
|
||||
cb_info["why"] = "刷新次数达到上限";
|
||||
cb_info["details"] = json::object{
|
||||
{ "refresh_limit", refresh_limit }
|
||||
};
|
||||
cb_info["details"] = json::object { { "refresh_limit", refresh_limit } };
|
||||
callback(AsstMsg::SubTaskError, cb_info);
|
||||
return {};
|
||||
}
|
||||
@@ -483,10 +488,7 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
|
||||
{
|
||||
json::value cb_info = basic_info();
|
||||
cb_info["what"] = "RecruitTagsRefreshed";
|
||||
cb_info["details"] = json::object{
|
||||
{ "count", refresh_count },
|
||||
{ "refresh_limit", refresh_limit }
|
||||
};
|
||||
cb_info["details"] = json::object { { "count", refresh_count }, { "refresh_limit", refresh_limit } };
|
||||
callback(AsstMsg::SubTaskExtraInfo, cb_info);
|
||||
Log.trace("recruit tags refreshed", std::to_string(refresh_count), " times, rerunning recruit task");
|
||||
}
|
||||
@@ -544,8 +546,7 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
|
||||
|
||||
// select tags
|
||||
for (const std::string& final_tag_name : final_combination.tags) {
|
||||
auto tag_rect_iter =
|
||||
ranges::find_if(tags, [&](const TextRect& r) { return r.text == final_tag_name; });
|
||||
auto tag_rect_iter = ranges::find_if(tags, [&](const TextRect& r) { return r.text == final_tag_name; });
|
||||
if (tag_rect_iter != tags.cend()) {
|
||||
m_ctrler->click(tag_rect_iter->rect);
|
||||
}
|
||||
@@ -554,9 +555,7 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
|
||||
{
|
||||
json::value cb_info = basic_info();
|
||||
cb_info["what"] = "RecruitTagsSelected";
|
||||
cb_info["details"] = json::object{
|
||||
{ "tags", json::array(final_combination.tags) }
|
||||
};
|
||||
cb_info["details"] = json::object { { "tags", json::array(final_combination.tags) } };
|
||||
callback(AsstMsg::SubTaskExtraInfo, cb_info);
|
||||
}
|
||||
|
||||
@@ -641,7 +640,7 @@ bool asst::AutoRecruitTask::hire_all(const cv::Mat& image)
|
||||
if (hire_searcher.get_result().empty()) return true;
|
||||
}
|
||||
// hire all
|
||||
return ProcessTask{ *this, { "RecruitFinish" }}.run();
|
||||
return ProcessTask { *this, { "RecruitFinish" } }.run();
|
||||
}
|
||||
|
||||
/// search for blue *Hire* buttons in the recruit home page, mark those slot clean and do hiring
|
||||
@@ -655,7 +654,7 @@ bool asst::AutoRecruitTask::hire_all()
|
||||
{
|
||||
m_dirty_slots.clear();
|
||||
const auto result = start_recruit_analyze(image);
|
||||
for (const TextRect& r: result) {
|
||||
for (const TextRect& r : result) {
|
||||
m_dirty_slots.emplace(slot_index_from_rect(r.rect));
|
||||
}
|
||||
Log.info("Dirty slots are", m_dirty_slots);
|
||||
@@ -666,15 +665,11 @@ void asst::AutoRecruitTask::async_upload_result(const json::value& details)
|
||||
{
|
||||
LogTraceFunction;
|
||||
if (m_upload_to_penguin) {
|
||||
auto upload_future = std::async(
|
||||
std::launch::async,
|
||||
&AutoRecruitTask::upload_to_penguin, this, details);
|
||||
auto upload_future = std::async(std::launch::async, &AutoRecruitTask::upload_to_penguin, this, details);
|
||||
m_upload_pending.emplace_back(std::move(upload_future));
|
||||
}
|
||||
if (m_upload_to_yituliu) {
|
||||
auto upload_future = std::async(
|
||||
std::launch::async,
|
||||
&AutoRecruitTask::upload_to_yituliu, this, details);
|
||||
auto upload_future = std::async(std::launch::async, &AutoRecruitTask::upload_to_yituliu, this, details);
|
||||
m_upload_pending.emplace_back(std::move(upload_future));
|
||||
}
|
||||
}
|
||||
@@ -694,17 +689,13 @@ void asst::AutoRecruitTask::upload_to_penguin(const json::value& details)
|
||||
body["stageId"] = "recruit";
|
||||
auto& all_drops = body["drops"];
|
||||
for (const auto& tag : details.at("tags").as_array()) {
|
||||
all_drops.array_emplace(json::object{
|
||||
{ "dropType", "NORMAL_DROP" },
|
||||
{ "itemId", tag.as_string() },
|
||||
{ "quantity", 1 }
|
||||
});
|
||||
all_drops.array_emplace(
|
||||
json::object { { "dropType", "NORMAL_DROP" }, { "itemId", tag.as_string() }, { "quantity", 1 } });
|
||||
}
|
||||
body["source"] = "MeoAssistant";
|
||||
body["version"] = Version;
|
||||
|
||||
std::string body_escape = utils::string_replace_all_batch(body.to_string(), {
|
||||
{"\"", "\\\""} });
|
||||
std::string body_escape = utils::string_replace_all_batch(body.to_string(), { { "\"", "\\\"" } });
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string body_escapes = utils::utf8_to_unicode_escape(body_escape);
|
||||
@@ -716,9 +707,8 @@ void asst::AutoRecruitTask::upload_to_penguin(const json::value& details)
|
||||
if (!m_penguin_id.empty()) {
|
||||
extra_param = "-H \"authorization: PenguinID " + m_penguin_id + "\"";
|
||||
}
|
||||
std::string cmd_line = utils::string_replace_all_batch(opt.penguin_report.cmd_format, {
|
||||
{ "[body]", body_escapes },
|
||||
{ "[extra]", extra_param } });
|
||||
std::string cmd_line = utils::string_replace_all_batch(opt.penguin_report.cmd_format,
|
||||
{ { "[body]", body_escapes }, { "[extra]", extra_param } });
|
||||
|
||||
Log.trace("request_penguin |", cmd_line);
|
||||
|
||||
@@ -754,8 +744,7 @@ void asst::AutoRecruitTask::upload_to_yituliu(const json::value& details)
|
||||
body["version"] = Version;
|
||||
body["uuid"] = m_yituliu_id;
|
||||
|
||||
std::string body_escape = utils::string_replace_all_batch(body.to_string(), {
|
||||
{"\"", "\\\""} });
|
||||
std::string body_escape = utils::string_replace_all_batch(body.to_string(), { { "\"", "\\\"" } });
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string body_escapes = utils::utf8_to_unicode_escape(body_escape);
|
||||
@@ -763,9 +752,8 @@ void asst::AutoRecruitTask::upload_to_yituliu(const json::value& details)
|
||||
std::string body_escapes = body_escape;
|
||||
#endif
|
||||
|
||||
std::string cmd_line = utils::string_replace_all_batch(opt.yituliu_report.cmd_format, {
|
||||
{ "[body]", body_escapes },
|
||||
{ "[extra]", "" } });
|
||||
std::string cmd_line = utils::string_replace_all_batch(opt.yituliu_report.cmd_format,
|
||||
{ { "[body]", body_escapes }, { "[extra]", "" } });
|
||||
|
||||
Log.trace("request_yituliu |", cmd_line);
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
#include "AsstTypes.h"
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <optional>
|
||||
#include <future>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace asst
|
||||
{
|
||||
@@ -76,12 +76,11 @@ namespace asst
|
||||
int m_slot_fail = 0;
|
||||
int m_cur_times = 0;
|
||||
|
||||
|
||||
std::set<slot_index> m_force_skipped;
|
||||
|
||||
// Do not report tags from these slot. Already reported, or we can not make sure whether it has been reported.
|
||||
// e.g. those that were already empty (*Recruit Now*) when we open the recruit page,
|
||||
// because we can not make sure whether they were already reported yesterday but stayed untouched for some reason
|
||||
// e.g. those that were already empty (*Recruit Now*) when we open the recruit page, because
|
||||
// we can not make sure whether they were already reported yesterday but stayed untouched for some reason.
|
||||
std::set<slot_index> m_dirty_slots = { 0, 1, 2, 3 };
|
||||
|
||||
std::string m_server = "CN";
|
||||
@@ -101,4 +100,4 @@ namespace asst
|
||||
return (cx > 640) + 2 * (cy > 444);
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
asst::AwardTask::AwardTask(AsstCallback callback, void* callback_arg)
|
||||
: PackageTask(std::move(callback), callback_arg, TaskType),
|
||||
m_award_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType))
|
||||
m_award_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType))
|
||||
{
|
||||
m_award_task_ptr->set_tasks({ "AwardBegin" });
|
||||
m_subtasks.emplace_back(m_award_task_ptr);
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace asst
|
||||
virtual ~AwardTask() override = default;
|
||||
|
||||
static constexpr const char* TaskType = "Award";
|
||||
|
||||
private:
|
||||
std::shared_ptr<ProcessTask> m_award_task_ptr = nullptr;
|
||||
};
|
||||
|
||||
@@ -10,18 +10,12 @@ bool asst::BattleDataConfiger::parse(const json::value& json)
|
||||
std::string name = char_data_json.at("name").as_string();
|
||||
data.name = name;
|
||||
static const std::unordered_map<std::string, BattleRole> RoleMap = {
|
||||
{ "CASTER", BattleRole::Caster },
|
||||
{ "MEDIC", BattleRole::Medic },
|
||||
{ "PIONEER", BattleRole::Pioneer },
|
||||
{ "SNIPER", BattleRole::Sniper},
|
||||
{ "SPECIAL", BattleRole::Special},
|
||||
{ "SUPPORT", BattleRole::Support},
|
||||
{ "TANK", BattleRole::Tank},
|
||||
{ "WARRIOR", BattleRole::Warrior},
|
||||
{ "CASTER", BattleRole::Caster }, { "MEDIC", BattleRole::Medic }, { "PIONEER", BattleRole::Pioneer },
|
||||
{ "SNIPER", BattleRole::Sniper }, { "SPECIAL", BattleRole::Special }, { "SUPPORT", BattleRole::Support },
|
||||
{ "TANK", BattleRole::Tank }, { "WARRIOR", BattleRole::Warrior },
|
||||
};
|
||||
|
||||
if (auto iter = RoleMap.find(char_data_json.at("profession").as_string());
|
||||
iter == RoleMap.cend()) {
|
||||
if (auto iter = RoleMap.find(char_data_json.at("profession").as_string()); iter == RoleMap.cend()) {
|
||||
data.role = BattleRole::Drone;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "AsstTypes.h"
|
||||
#include "AsstBattleDef.h"
|
||||
#include "AsstTypes.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace asst
|
||||
return iter->second.rarity;
|
||||
}
|
||||
|
||||
static inline const BattleAttackRange& EmptyRange{ {0, 0} };
|
||||
static inline const BattleAttackRange& EmptyRange { { 0, 0 } };
|
||||
|
||||
const BattleAttackRange& get_range(const std::string& name, size_t index) const
|
||||
{
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include "AsstRanges.hpp"
|
||||
|
||||
#include "Resource.h"
|
||||
#include "Controller.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "OcrWithFlagTemplImageAnalyzer.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "Resource.h"
|
||||
|
||||
#include "AsstRanges.hpp"
|
||||
|
||||
@@ -80,22 +80,18 @@ bool asst::BattleFormationTask::select_opers_in_cur_page()
|
||||
}
|
||||
|
||||
// 按位置排个序
|
||||
ranges::sort(opers_result,
|
||||
[](const TextRect& lhs, const TextRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
ranges::sort(opers_result, [](const TextRect& lhs, const TextRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
);
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
});
|
||||
|
||||
static const std::array<Rect, 3> SkillRectArray = {
|
||||
Task.get("BattleQuickFormationSkill1")->specific_rect,
|
||||
Task.get("BattleQuickFormationSkill2")->specific_rect,
|
||||
Task.get("BattleQuickFormationSkill3")->specific_rect
|
||||
};
|
||||
static const std::array<Rect, 3> SkillRectArray = { Task.get("BattleQuickFormationSkill1")->specific_rect,
|
||||
Task.get("BattleQuickFormationSkill2")->specific_rect,
|
||||
Task.get("BattleQuickFormationSkill3")->specific_rect };
|
||||
|
||||
int skill = 1;
|
||||
for (const auto& res : opers_result) {
|
||||
@@ -141,8 +137,7 @@ void asst::BattleFormationTask::swipe_page()
|
||||
static Rect end_rect = Task.get("InfrastOperListSwipeEnd")->specific_rect;
|
||||
static int duration = Task.get("InfrastOperListSwipeBegin")->pre_delay;
|
||||
|
||||
m_ctrler->swipe(begin_rect, end_rect,
|
||||
duration, true, Task.get("InfrastOperListSwipeBegin")->rear_delay, true);
|
||||
m_ctrler->swipe(begin_rect, end_rect, duration, true, Task.get("InfrastOperListSwipeBegin")->rear_delay, true);
|
||||
}
|
||||
|
||||
bool asst::BattleFormationTask::confirm_selection()
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#include "BattleImageAnalyzer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "AsstRanges.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#include "NoWarningCV.h"
|
||||
|
||||
#include "MultiMatchImageAnalyzer.h"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "OcrWithFlagTemplImageAnalyzer.h"
|
||||
#include "HashImageAnalyzer.h"
|
||||
#include "Logger.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "MultiMatchImageAnalyzer.h"
|
||||
#include "OcrWithFlagTemplImageAnalyzer.h"
|
||||
#include "TaskData.h"
|
||||
|
||||
bool asst::BattleImageAnalyzer::set_target(int target)
|
||||
@@ -171,8 +171,8 @@ bool asst::BattleImageAnalyzer::opers_analyze()
|
||||
oper.role = oper_role_analyze(role_rect);
|
||||
|
||||
// 费用识别的不太准,暂时也没用上,先注释掉,TODO:优化费用识别
|
||||
//Rect cost_rect = flag_mrect.rect.move(cost_move);
|
||||
//oper.cost = oper_cost_analyze(cost_rect);
|
||||
// Rect cost_rect = flag_mrect.rect.move(cost_move);
|
||||
// oper.cost = oper_cost_analyze(cost_rect);
|
||||
oper.index = index++;
|
||||
|
||||
m_opers.emplace_back(std::move(oper));
|
||||
@@ -184,15 +184,9 @@ bool asst::BattleImageAnalyzer::opers_analyze()
|
||||
asst::BattleRole asst::BattleImageAnalyzer::oper_role_analyze(const Rect& roi)
|
||||
{
|
||||
static const std::unordered_map<BattleRole, std::string> RolesName = {
|
||||
{ BattleRole::Caster, "Caster" },
|
||||
{ BattleRole::Medic, "Medic" },
|
||||
{ BattleRole::Pioneer, "Pioneer" },
|
||||
{ BattleRole::Sniper, "Sniper" },
|
||||
{ BattleRole::Special, "Special" },
|
||||
{ BattleRole::Support, "Support" },
|
||||
{ BattleRole::Tank, "Tank" },
|
||||
{ BattleRole::Warrior, "Warrior" },
|
||||
{ BattleRole::Drone, "Drone" }
|
||||
{ BattleRole::Caster, "Caster" }, { BattleRole::Medic, "Medic" }, { BattleRole::Pioneer, "Pioneer" },
|
||||
{ BattleRole::Sniper, "Sniper" }, { BattleRole::Special, "Special" }, { BattleRole::Support, "Support" },
|
||||
{ BattleRole::Tank, "Tank" }, { BattleRole::Warrior, "Warrior" }, { BattleRole::Drone, "Drone" }
|
||||
};
|
||||
|
||||
MatchImageAnalyzer role_analyzer(m_image);
|
||||
@@ -205,8 +199,7 @@ asst::BattleRole asst::BattleImageAnalyzer::oper_role_analyze(const Rect& roi)
|
||||
if (!role_analyzer.analyze()) {
|
||||
continue;
|
||||
}
|
||||
if (double cur_score = role_analyzer.get_result().score;
|
||||
max_score < cur_score) {
|
||||
if (double cur_score = role_analyzer.get_result().score; max_score < cur_score) {
|
||||
result = role;
|
||||
max_score = cur_score;
|
||||
}
|
||||
@@ -214,8 +207,7 @@ asst::BattleRole asst::BattleImageAnalyzer::oper_role_analyze(const Rect& roi)
|
||||
|
||||
#ifdef ASST_DEBUG
|
||||
std::string role_name;
|
||||
if (auto iter = RolesName.find(result);
|
||||
iter == RolesName.cend()) {
|
||||
if (auto iter = RolesName.find(result); iter == RolesName.cend()) {
|
||||
role_name = "Unknown";
|
||||
}
|
||||
else {
|
||||
@@ -259,26 +251,20 @@ bool asst::BattleImageAnalyzer::oper_cooling_analyze(const Rect& roi)
|
||||
|
||||
int asst::BattleImageAnalyzer::oper_cost_analyze(const Rect& roi)
|
||||
{
|
||||
static const std::array<std::string, 10> NumName = {
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
|
||||
};
|
||||
static const std::array<std::string, 10> NumName = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
static bool inited = false;
|
||||
static cv::Scalar range_lower, range_upper;
|
||||
|
||||
static HashImageAnalyzer hash_analyzer;
|
||||
if (!inited) {
|
||||
auto [h_l, h_u] = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleOperCostChannelH"))->mask_range;
|
||||
auto [s_l, s_u] = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleOperCostChannelS"))->mask_range;
|
||||
auto [v_l, v_u] = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleOperCostChannelV"))->mask_range;
|
||||
auto [h_l, h_u] = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleOperCostChannelH"))->mask_range;
|
||||
auto [s_l, s_u] = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleOperCostChannelS"))->mask_range;
|
||||
auto [v_l, v_u] = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleOperCostChannelV"))->mask_range;
|
||||
range_lower = cv::Scalar(h_l, s_l, v_l);
|
||||
range_upper = cv::Scalar(h_u, s_u, v_u);
|
||||
std::unordered_map<std::string, std::string> num_hashs;
|
||||
for (auto&& num : NumName) {
|
||||
auto hashs_vec = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleOperCost" + num))->hashes;
|
||||
auto hashs_vec = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleOperCost" + num))->hashes;
|
||||
for (size_t i = 0; i != hashs_vec.size(); ++i) {
|
||||
num_hashs.emplace(num + "_" + std::to_string(i), hashs_vec.at(i));
|
||||
}
|
||||
@@ -320,8 +306,7 @@ bool asst::BattleImageAnalyzer::oper_available_analyze(const Rect& roi)
|
||||
cv::Scalar avg = cv::mean(hsv);
|
||||
Log.trace("oper available, mean", avg[2]);
|
||||
|
||||
static int thres = static_cast<int>(
|
||||
Task.get<MatchTaskInfo>("BattleOperAvailable")->special_threshold);
|
||||
static int thres = static_cast<int>(Task.get<MatchTaskInfo>("BattleOperAvailable")->special_threshold);
|
||||
if (avg[2] < thres) {
|
||||
return false;
|
||||
}
|
||||
@@ -403,25 +388,19 @@ bool asst::BattleImageAnalyzer::hp_analyze()
|
||||
Rect roi_rect = flag_analyzer.get_result().rect.move(flag_task_ptr->rect_move);
|
||||
cv::Mat roi = m_image(utils::make_rect<cv::Rect>(roi_rect));
|
||||
|
||||
static const std::array<std::string, 10> NumName = {
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
|
||||
};
|
||||
static const std::array<std::string, 10> NumName = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
static bool inited = false;
|
||||
static cv::Scalar range_lower, range_upper;
|
||||
static HashImageAnalyzer hash_analyzer;
|
||||
if (!inited) {
|
||||
auto [h_l, h_u] = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleHpChannelH"))->mask_range;
|
||||
auto [s_l, s_u] = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleHpChannelS"))->mask_range;
|
||||
auto [v_l, v_u] = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleHpChannelV"))->mask_range;
|
||||
auto [h_l, h_u] = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleHpChannelH"))->mask_range;
|
||||
auto [s_l, s_u] = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleHpChannelS"))->mask_range;
|
||||
auto [v_l, v_u] = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleHpChannelV"))->mask_range;
|
||||
range_lower = cv::Scalar(h_l, s_l, v_l);
|
||||
range_upper = cv::Scalar(h_u, s_u, v_u);
|
||||
std::unordered_map<std::string, std::string> num_hashs;
|
||||
for (auto&& num : NumName) {
|
||||
const auto& hashs_vec = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("BattleHp" + num))->hashes;
|
||||
const auto& hashs_vec = std::dynamic_pointer_cast<HashTaskInfo>(Task.get("BattleHp" + num))->hashes;
|
||||
for (size_t i = 0; i != hashs_vec.size(); ++i) {
|
||||
num_hashs.emplace(num + "_" + std::to_string(i), hashs_vec.at(i));
|
||||
}
|
||||
@@ -450,7 +429,8 @@ bool asst::BattleImageAnalyzer::hp_analyze()
|
||||
}
|
||||
|
||||
#ifdef ASST_DEBUG
|
||||
cv::putText(m_image_draw, "HP: " + std::to_string(hp), cv::Point(roi_rect.x, roi_rect.y + 50), 2, 1, cv::Scalar(0, 0, 255));
|
||||
cv::putText(m_image_draw, "HP: " + std::to_string(hp), cv::Point(roi_rect.x, roi_rect.y + 50), 2, 1,
|
||||
cv::Scalar(0, 0, 255));
|
||||
#endif
|
||||
m_hp = hp;
|
||||
return true;
|
||||
@@ -460,8 +440,7 @@ bool asst::BattleImageAnalyzer::kills_analyze()
|
||||
{
|
||||
OcrWithFlagTemplImageAnalyzer kills_analyzer(m_image);
|
||||
kills_analyzer.set_task_info("BattleKillsFlag", "BattleKills");
|
||||
kills_analyzer.set_replace(
|
||||
Task.get<OcrTaskInfo>("NumberOcrReplace")->replace_map);
|
||||
kills_analyzer.set_replace(Task.get<OcrTaskInfo>("NumberOcrReplace")->replace_map);
|
||||
|
||||
if (!kills_analyzer.analyze()) {
|
||||
return false;
|
||||
@@ -500,9 +479,7 @@ bool asst::BattleImageAnalyzer::kills_analyze()
|
||||
|
||||
// 例子中的"0"
|
||||
std::string kills_count = kills_text.substr(0, pos);
|
||||
if (kills_count.empty() ||
|
||||
!ranges::all_of(kills_count,
|
||||
[](char c) -> bool {return std::isdigit(c);})) {
|
||||
if (kills_count.empty() || !ranges::all_of(kills_count, [](char c) -> bool { return std::isdigit(c); })) {
|
||||
return false;
|
||||
}
|
||||
int cur_kills = std::stoi(kills_count);
|
||||
@@ -511,9 +488,7 @@ bool asst::BattleImageAnalyzer::kills_analyze()
|
||||
// 例子中的"41"
|
||||
std::string total_kills = kills_text.substr(pos + 1, std::string::npos);
|
||||
int cur_total_kills = 0;
|
||||
if (total_kills.empty() ||
|
||||
!ranges::all_of(total_kills,
|
||||
[](char c) -> bool {return std::isdigit(c);})) {
|
||||
if (total_kills.empty() || !ranges::all_of(total_kills, [](char c) -> bool { return std::isdigit(c); })) {
|
||||
Log.warn("total kills recognition failed, set to", m_pre_total_kills);
|
||||
cur_total_kills = m_pre_total_kills;
|
||||
}
|
||||
@@ -530,8 +505,7 @@ bool asst::BattleImageAnalyzer::cost_analyze()
|
||||
{
|
||||
OcrWithPreprocessImageAnalyzer cost_analyzer(m_image);
|
||||
cost_analyzer.set_task_info("BattleCostData");
|
||||
cost_analyzer.set_replace(
|
||||
Task.get<OcrTaskInfo>("NumberOcrReplace")->replace_map);
|
||||
cost_analyzer.set_replace(Task.get<OcrTaskInfo>("NumberOcrReplace")->replace_map);
|
||||
|
||||
if (!cost_analyzer.analyze()) {
|
||||
return false;
|
||||
@@ -539,9 +513,7 @@ bool asst::BattleImageAnalyzer::cost_analyze()
|
||||
|
||||
std::string cost_str = cost_analyzer.get_result().front().text;
|
||||
|
||||
if (cost_str.empty() ||
|
||||
!ranges::all_of(cost_str,
|
||||
[](const char& c) -> bool {return std::isdigit(c);})) {
|
||||
if (cost_str.empty() || !ranges::all_of(cost_str, [](const char& c) -> bool { return std::isdigit(c); })) {
|
||||
return false;
|
||||
}
|
||||
m_cost = std::stoi(cost_str);
|
||||
|
||||
@@ -8,19 +8,20 @@ namespace asst
|
||||
class BattleImageAnalyzer : public AbstractImageAnalyzer
|
||||
{
|
||||
public:
|
||||
enum Target // 需要识别的目标
|
||||
enum Target // 需要识别的目标
|
||||
{
|
||||
None = 0,
|
||||
HP = 1, // 剩余生命值
|
||||
Home = 2, // 蓝色的家门
|
||||
Oper = 4, // 下方的干员信息
|
||||
Skill = 8, // cd 转好了可以使用的技能
|
||||
Kills = 16, // 击杀数
|
||||
Cost = 32, // 费用
|
||||
Vacancies = 64, // 剩余可部署干员数
|
||||
HP = 1, // 剩余生命值
|
||||
Home = 2, // 蓝色的家门
|
||||
Oper = 4, // 下方的干员信息
|
||||
Skill = 8, // cd 转好了可以使用的技能
|
||||
Kills = 16, // 击杀数
|
||||
Cost = 32, // 费用
|
||||
Vacancies = 64, // 剩余可部署干员数
|
||||
// 肉鸽模式需要用到的识别
|
||||
Roguelike = Home | Oper
|
||||
};
|
||||
|
||||
public:
|
||||
using AbstractImageAnalyzer::AbstractImageAnalyzer;
|
||||
virtual ~BattleImageAnalyzer() override = default;
|
||||
@@ -39,33 +40,33 @@ namespace asst
|
||||
int get_cost() const noexcept;
|
||||
|
||||
void clear() noexcept;
|
||||
void sort_opers_by_cost(); // 高费在前,费用降序
|
||||
void sort_opers_by_cost(); // 高费在前,费用降序
|
||||
|
||||
protected:
|
||||
bool opers_analyze(); // 识别干员
|
||||
bool opers_analyze(); // 识别干员
|
||||
BattleRole oper_role_analyze(const Rect& roi);
|
||||
bool oper_cooling_analyze(const Rect& roi);
|
||||
int oper_cost_analyze(const Rect& roi);
|
||||
bool oper_available_analyze(const Rect& roi);
|
||||
|
||||
bool home_analyze(); // 识别蓝色的家门
|
||||
bool skill_analyze(); // 识别技能是否可用
|
||||
bool hp_analyze(); // 识别剩余生命值
|
||||
bool kills_analyze(); // 识别击杀数
|
||||
bool cost_analyze(); // 识别费用
|
||||
bool vacancies_analyze();// 识别剩余可部署人数
|
||||
bool flag_analyze(); // 识别暂停按钮
|
||||
bool home_analyze(); // 识别蓝色的家门
|
||||
bool skill_analyze(); // 识别技能是否可用
|
||||
bool hp_analyze(); // 识别剩余生命值
|
||||
bool kills_analyze(); // 识别击杀数
|
||||
bool cost_analyze(); // 识别费用
|
||||
bool vacancies_analyze(); // 识别剩余可部署人数
|
||||
bool flag_analyze(); // 识别暂停按钮
|
||||
|
||||
int m_target = 0; // 待识别的目标
|
||||
int m_pre_total_kills = 0; // 之前的击杀总数,因为击杀数经常识别不准所以依赖外部传入作为参考
|
||||
int m_target = 0; // 待识别的目标
|
||||
int m_pre_total_kills = 0; // 之前的击杀总数,因为击杀数经常识别不准所以依赖外部传入作为参考
|
||||
|
||||
/* 识别结果缓存 */
|
||||
std::vector<BattleRealTimeOper> m_opers; // 下方干员信息
|
||||
std::vector<Rect> m_homes; // 蓝色的家门位置
|
||||
std::vector<Rect> m_ready_skills; // 可以释放的技能(Rect实际是干员的位置)
|
||||
int m_hp = 0; // 剩余生命值
|
||||
int m_kills = 0; // 击杀数
|
||||
int m_total_kills = 0; // 击杀总数
|
||||
int m_cost = 0; // 部署费用
|
||||
std::vector<BattleRealTimeOper> m_opers; // 下方干员信息
|
||||
std::vector<Rect> m_homes; // 蓝色的家门位置
|
||||
std::vector<Rect> m_ready_skills; // 可以释放的技能(Rect实际是干员的位置)
|
||||
int m_hp = 0; // 剩余生命值
|
||||
int m_kills = 0; // 击杀数
|
||||
int m_total_kills = 0; // 击杀总数
|
||||
int m_cost = 0; // 部署费用
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
#include "BattleProcessTask.h"
|
||||
|
||||
#include <thread>
|
||||
#include "AsstRanges.hpp"
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include "AsstRanges.hpp"
|
||||
#include <thread>
|
||||
|
||||
#include "NoWarningCV.h"
|
||||
|
||||
#include "Controller.h"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
#include "TaskData.h"
|
||||
#include "Logger.hpp"
|
||||
|
||||
#include "ProcessTask.h"
|
||||
|
||||
#include "BattleImageAnalyzer.h"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "OcrWithPreprocessImageAnalyzer.h"
|
||||
#include "BattleImageAnalyzer.h"
|
||||
|
||||
void asst::BattleProcessTask::set_stage_name(std::string name)
|
||||
{
|
||||
@@ -167,8 +167,7 @@ bool asst::BattleProcessTask::analyze_opers_preview()
|
||||
|
||||
OcrWithPreprocessImageAnalyzer name_analyzer(image);
|
||||
name_analyzer.set_task_info("BattleOperName");
|
||||
name_analyzer.set_replace(
|
||||
Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
name_analyzer.set_replace(Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
|
||||
std::string oper_name = "Unknown";
|
||||
if (name_analyzer.analyze()) {
|
||||
@@ -180,10 +179,8 @@ bool asst::BattleProcessTask::analyze_opers_preview()
|
||||
bool not_found = true;
|
||||
// 找出这个干员是哪个组里的,以及他的技能用法等
|
||||
for (const auto& [group_name, deploy_opers] : m_copilot_data.groups) {
|
||||
auto iter = ranges::find_if(deploy_opers,
|
||||
[&](const BattleDeployOper& deploy) -> bool {
|
||||
return deploy.name == oper_name;
|
||||
});
|
||||
auto iter = ranges::find_if(
|
||||
deploy_opers, [&](const BattleDeployOper& deploy) -> bool { return deploy.name == oper_name; });
|
||||
if (iter != deploy_opers.cend()) {
|
||||
m_group_to_oper_mapping.emplace(group_name, *iter);
|
||||
not_found = false;
|
||||
@@ -192,7 +189,7 @@ bool asst::BattleProcessTask::analyze_opers_preview()
|
||||
}
|
||||
// 没找到,可能是召唤物等新出现的
|
||||
if (not_found) {
|
||||
m_group_to_oper_mapping.emplace(oper_name, BattleDeployOper{ oper_name });
|
||||
m_group_to_oper_mapping.emplace(oper_name, BattleDeployOper { oper_name });
|
||||
}
|
||||
|
||||
m_cur_opers_info.emplace(std::move(oper_name), std::move(opers.at(i)));
|
||||
@@ -280,14 +277,13 @@ bool asst::BattleProcessTask::update_opers_info(const cv::Mat& image)
|
||||
|
||||
OcrWithPreprocessImageAnalyzer name_analyzer(m_ctrler->get_image());
|
||||
name_analyzer.set_task_info("BattleOperName");
|
||||
name_analyzer.set_replace(
|
||||
Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
name_analyzer.set_replace(Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
|
||||
if (name_analyzer.analyze()) {
|
||||
name_analyzer.sort_result_by_score();
|
||||
oper_name = name_analyzer.get_result().front().text;
|
||||
}
|
||||
m_group_to_oper_mapping[oper_name] = BattleDeployOper{ oper_name };
|
||||
m_group_to_oper_mapping[oper_name] = BattleDeployOper { oper_name };
|
||||
m_ctrler->click(cur_oper.rect);
|
||||
sleep(Task.get("BattleUseOper")->pre_delay);
|
||||
battle_pause();
|
||||
@@ -366,8 +362,7 @@ bool asst::BattleProcessTask::do_action(const BattleAction& action)
|
||||
case BattleActionType::BulletTime:
|
||||
// TODO
|
||||
break;
|
||||
case BattleActionType::SkillUsage:
|
||||
{
|
||||
case BattleActionType::SkillUsage: {
|
||||
auto& oper_info = m_group_to_oper_mapping[action.group_name];
|
||||
oper_info.skill_usage = action.modify_usage;
|
||||
m_used_opers[oper_info.name].info.skill_usage = action.modify_usage;
|
||||
@@ -452,8 +447,7 @@ bool asst::BattleProcessTask::wait_condition(const BattleAction& action)
|
||||
}
|
||||
update_opers_info(image);
|
||||
|
||||
if (auto iter = m_cur_opers_info.find(name);
|
||||
iter != m_cur_opers_info.cend() && iter->second.available) {
|
||||
if (auto iter = m_cur_opers_info.find(name); iter != m_cur_opers_info.cend() && iter->second.available) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -487,9 +481,9 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action)
|
||||
// 拖动到场上
|
||||
Point placed_point = m_side_tile_info[action.location].pos;
|
||||
|
||||
Rect placed_rect{ placed_point.x ,placed_point.y, 0, 0 };
|
||||
int dist = static_cast<int>(Point::distance(
|
||||
placed_point, { oper_rect.x + oper_rect.width / 2, oper_rect.y + oper_rect.height / 2 }));
|
||||
Rect placed_rect { placed_point.x, placed_point.y, 0, 0 };
|
||||
int dist = static_cast<int>(
|
||||
Point::distance(placed_point, { oper_rect.x + oper_rect.width / 2, oper_rect.y + oper_rect.height / 2 }));
|
||||
// 1000 是随便取的一个系数,把整数的 pre_delay 转成小数用的
|
||||
int duration = static_cast<int>(swipe_oper_task_ptr->pre_delay / 1000.0 * dist * log10(dist));
|
||||
m_ctrler->swipe(oper_rect, placed_rect, duration, true, 0);
|
||||
@@ -499,11 +493,9 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action)
|
||||
// 拖动干员朝向
|
||||
if (action.direction != BattleDeployDirection::None) {
|
||||
static const std::unordered_map<BattleDeployDirection, Point> DirectionMapping = {
|
||||
{ BattleDeployDirection::Right, Point(1, 0)},
|
||||
{ BattleDeployDirection::Down, Point(0, 1)},
|
||||
{ BattleDeployDirection::Left, Point(-1, 0)},
|
||||
{ BattleDeployDirection::Up, Point(0, -1)},
|
||||
{ BattleDeployDirection::None, Point(0, 0)},
|
||||
{ BattleDeployDirection::Right, Point(1, 0) }, { BattleDeployDirection::Down, Point(0, 1) },
|
||||
{ BattleDeployDirection::Left, Point(-1, 0) }, { BattleDeployDirection::Up, Point(0, -1) },
|
||||
{ BattleDeployDirection::None, Point(0, 0) },
|
||||
};
|
||||
|
||||
// 计算往哪边拖动
|
||||
@@ -516,14 +508,12 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action)
|
||||
m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->rear_delay, true, 100);
|
||||
}
|
||||
|
||||
m_used_opers[iter->first] = BattleDeployInfo{
|
||||
action.location,
|
||||
m_normal_tile_info[action.location].pos,
|
||||
oper_info };
|
||||
m_used_opers[iter->first] =
|
||||
BattleDeployInfo { action.location, m_normal_tile_info[action.location].pos, oper_info };
|
||||
|
||||
m_cur_opers_info.erase(iter);
|
||||
|
||||
//sleep(use_oper_task_ptr->pre_delay);
|
||||
// sleep(use_oper_task_ptr->pre_delay);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -533,8 +523,7 @@ bool asst::BattleProcessTask::oper_retreat(const BattleAction& action)
|
||||
const std::string& name = m_group_to_oper_mapping[action.group_name].name;
|
||||
Point pos;
|
||||
if (auto iter = m_used_opers.find(name);
|
||||
action.location.x == 0 && action.location.y == 0 &&
|
||||
iter != m_used_opers.cend()) {
|
||||
action.location.x == 0 && action.location.y == 0 && iter != m_used_opers.cend()) {
|
||||
pos = iter->second.pos;
|
||||
m_used_opers.erase(iter);
|
||||
}
|
||||
@@ -552,8 +541,7 @@ bool asst::BattleProcessTask::use_skill(const BattleAction& action)
|
||||
const std::string& name = m_group_to_oper_mapping[action.group_name].name;
|
||||
Point pos;
|
||||
if (auto iter = m_used_opers.find(name);
|
||||
action.location.x == 0 && action.location.y == 0 &&
|
||||
iter != m_used_opers.cend()) {
|
||||
action.location.x == 0 && action.location.y == 0 && iter != m_used_opers.cend()) {
|
||||
pos = iter->second.pos;
|
||||
}
|
||||
else {
|
||||
@@ -597,11 +585,10 @@ bool asst::BattleProcessTask::try_possible_skill(const cv::Mat& image)
|
||||
analyzer.set_task_info(task_ptr);
|
||||
bool used = false;
|
||||
for (auto& info : m_used_opers | views::values) {
|
||||
if (info.info.skill_usage != BattleSkillUsage::Possibly
|
||||
&& info.info.skill_usage != BattleSkillUsage::Once) {
|
||||
if (info.info.skill_usage != BattleSkillUsage::Possibly && info.info.skill_usage != BattleSkillUsage::Once) {
|
||||
continue;
|
||||
}
|
||||
const Rect roi = Rect{ info.pos.x, info.pos.y, 0, 0 }.move(skill_roi_move);
|
||||
const Rect roi = Rect { info.pos.x, info.pos.y, 0, 0 }.move(skill_roi_move);
|
||||
analyzer.set_roi(roi);
|
||||
if (!analyzer.analyze()) {
|
||||
continue;
|
||||
@@ -630,8 +617,8 @@ void asst::BattleProcessTask::sleep_with_possible_skill(unsigned millisecond)
|
||||
Log.trace("ready to sleep_with_possible_skill", millisecond);
|
||||
|
||||
while (!need_exit() && duration < millisecond) {
|
||||
duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start).count();
|
||||
duration =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
||||
try_possible_skill(m_ctrler->get_image());
|
||||
std::this_thread::yield();
|
||||
}
|
||||
@@ -639,10 +626,9 @@ void asst::BattleProcessTask::sleep_with_possible_skill(unsigned millisecond)
|
||||
}
|
||||
|
||||
template <typename GroupNameType, typename CharNameType>
|
||||
std::optional<std::unordered_map<GroupNameType, CharNameType>>
|
||||
asst::BattleProcessTask::get_char_allocation_for_each_group(
|
||||
const std::unordered_map<GroupNameType, std::vector<CharNameType>>& group_list,
|
||||
const std::vector<CharNameType>& char_list)
|
||||
std::optional<std::unordered_map<GroupNameType, CharNameType>> asst::BattleProcessTask::
|
||||
get_char_allocation_for_each_group(const std::unordered_map<GroupNameType, std::vector<CharNameType>>& group_list,
|
||||
const std::vector<CharNameType>& char_list)
|
||||
{
|
||||
/*
|
||||
* * dlx 算法简介
|
||||
@@ -720,12 +706,11 @@ asst::BattleProcessTask::get_char_allocation_for_each_group(
|
||||
*
|
||||
*/
|
||||
|
||||
// dlx 算法模板类
|
||||
// dlx 算法模板类
|
||||
class DancingLinksModel
|
||||
{
|
||||
private:
|
||||
|
||||
size_t index{};
|
||||
size_t index {};
|
||||
std::vector<size_t> first, size;
|
||||
std::vector<size_t> left, right, up, down;
|
||||
std::vector<size_t> column, row;
|
||||
@@ -755,20 +740,12 @@ asst::BattleProcessTask::get_char_allocation_for_each_group(
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
size_t answer_stack_size{};
|
||||
size_t answer_stack_size {};
|
||||
std::vector<size_t> answer_stack;
|
||||
|
||||
DancingLinksModel(const size_t& max_node_num, const size_t& max_ans_size) :
|
||||
first(max_node_num),
|
||||
size(max_node_num),
|
||||
left(max_node_num),
|
||||
right(max_node_num),
|
||||
up(max_node_num),
|
||||
down(max_node_num),
|
||||
column(max_node_num),
|
||||
row(max_node_num),
|
||||
answer_stack(max_ans_size)
|
||||
DancingLinksModel(const size_t& max_node_num, const size_t& max_ans_size)
|
||||
: first(max_node_num), size(max_node_num), left(max_node_num), right(max_node_num), up(max_node_num),
|
||||
down(max_node_num), column(max_node_num), row(max_node_num), answer_stack(max_ans_size)
|
||||
{}
|
||||
|
||||
void build(const size_t& column_id)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#include "AbstractTask.h"
|
||||
|
||||
#include "AsstTypes.h"
|
||||
#include "TilePack.h"
|
||||
#include "AsstBattleDef.h"
|
||||
#include "AsstTypes.h"
|
||||
#include "BattleImageAnalyzer.h"
|
||||
#include "TilePack.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
asst::CloseDownTask::CloseDownTask(AsstCallback callback, void* callback_arg)
|
||||
: PackageTask(std::move(callback), callback_arg, TaskType),
|
||||
m_stop_game_task_ptr(std::make_shared<StopGameTaskPlugin>(m_callback, m_callback_arg, TaskType))
|
||||
m_stop_game_task_ptr(std::make_shared<StopGameTaskPlugin>(m_callback, m_callback_arg, TaskType))
|
||||
{
|
||||
m_subtasks.emplace_back(m_stop_game_task_ptr);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace asst
|
||||
virtual ~CloseDownTask() override = default;
|
||||
|
||||
static constexpr const char* TaskType = "CloseDown";
|
||||
|
||||
private:
|
||||
std::shared_ptr<StopGameTaskPlugin> m_stop_game_task_ptr = nullptr;
|
||||
};
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
#include "AsstConf.h"
|
||||
#include "Controller.h"
|
||||
#include "AsstConf.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WinUser.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "NoWarningCV.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable: 4068 )
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4068)
|
||||
#endif
|
||||
#include <zlib/decompress.hpp>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "AsstTypes.h"
|
||||
@@ -37,32 +37,23 @@
|
||||
class WsaHelper
|
||||
{
|
||||
public:
|
||||
~WsaHelper()
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
~WsaHelper() { WSACleanup(); }
|
||||
static WsaHelper& get_instance()
|
||||
{
|
||||
static WsaHelper instance;
|
||||
return instance;
|
||||
}
|
||||
bool operator()() const noexcept { return m_supports; }
|
||||
|
||||
private:
|
||||
WsaHelper()
|
||||
{
|
||||
m_supports =
|
||||
WSAStartup(MAKEWORD(2, 2), &m_wsa_data) == 0 &&
|
||||
m_wsa_data.wVersion == MAKEWORD(2, 2);
|
||||
}
|
||||
WsaHelper() { m_supports = WSAStartup(MAKEWORD(2, 2), &m_wsa_data) == 0 && m_wsa_data.wVersion == MAKEWORD(2, 2); }
|
||||
WSADATA m_wsa_data = { 0 };
|
||||
bool m_supports = false;
|
||||
};
|
||||
#endif
|
||||
|
||||
asst::Controller::Controller(AsstCallback callback, void* callback_arg)
|
||||
: m_callback(std::move(callback)),
|
||||
m_callback_arg(callback_arg),
|
||||
m_rand_engine(std::random_device{}())
|
||||
: m_callback(std::move(callback)), m_callback_arg(callback_arg), m_rand_engine(std::random_device {}())
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -128,7 +119,7 @@ asst::Controller::~Controller()
|
||||
LogTraceFunction;
|
||||
|
||||
m_thread_exit = true;
|
||||
//m_thread_idle = true;
|
||||
// m_thread_idle = true;
|
||||
m_cmd_condvar.notify_all();
|
||||
m_completed_id = UINT_MAX; // make all WinMacor::wait to exit
|
||||
|
||||
@@ -154,58 +145,58 @@ asst::Controller::~Controller()
|
||||
#endif
|
||||
}
|
||||
|
||||
//asst::Rect asst::Controller::shaped_correct(const Rect & rect) const
|
||||
// asst::Rect asst::Controller::shaped_correct(const Rect & rect) const
|
||||
//{
|
||||
// if (rect.empty()
|
||||
// || m_scale_size.first == 0
|
||||
// || m_scale_size.second == 0) {
|
||||
// return rect;
|
||||
// }
|
||||
// // 明日方舟在异形屏上,有的地方是按比例缩放的,有的地方又是直接位移。没法整,这里简单粗暴一点截一个长条
|
||||
// Rect dst = rect;
|
||||
// if (m_scale_size.first != WindowWidthDefault) { // 说明是宽屏
|
||||
// if (rect.width <= WindowWidthDefault / 2) {
|
||||
// if (rect.x + rect.width <= WindowWidthDefault / 2) { // 整个矩形都在左半边
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first / 2;
|
||||
// }
|
||||
// else if (rect.x >= WindowWidthDefault / 2) { // 整个矩形都在右半边
|
||||
// dst.x = m_scale_size.first / 2;
|
||||
// dst.width = m_scale_size.first / 2;
|
||||
// }
|
||||
// else { // 整个矩形横跨了中线
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first;
|
||||
// }
|
||||
// }
|
||||
// else if (m_scale_size.second != WindowHeightDefault) { // 说明是偏方形屏
|
||||
// if (rect.height <= WindowHeightDefault / 2) {
|
||||
// if (rect.y + rect.height <= WindowHeightDefault / 2) { // 整个矩形都在上半边
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second / 2;
|
||||
// }
|
||||
// else if (rect.y >= WindowHeightDefault / 2) { // 整个矩形都在下半边
|
||||
// dst.y = m_scale_size.second / 2;
|
||||
// dst.height = m_scale_size.second / 2; // 整个矩形横跨了中线
|
||||
// }
|
||||
// else {
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second;
|
||||
// }
|
||||
// }
|
||||
// if (rect.empty()
|
||||
// || m_scale_size.first == 0
|
||||
// || m_scale_size.second == 0) {
|
||||
// return rect;
|
||||
// }
|
||||
// // 明日方舟在异形屏上,有的地方是按比例缩放的,有的地方又是直接位移。没法整,这里简单粗暴一点截一个长条
|
||||
// Rect dst = rect;
|
||||
// if (m_scale_size.first != WindowWidthDefault) { // 说明是宽屏
|
||||
// if (rect.width <= WindowWidthDefault / 2) {
|
||||
// if (rect.x + rect.width <= WindowWidthDefault / 2) { // 整个矩形都在左半边
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first / 2;
|
||||
// }
|
||||
// else if (rect.x >= WindowWidthDefault / 2) { // 整个矩形都在右半边
|
||||
// dst.x = m_scale_size.first / 2;
|
||||
// dst.width = m_scale_size.first / 2;
|
||||
// }
|
||||
// else { // 整个矩形横跨了中线
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first;
|
||||
// }
|
||||
// }
|
||||
// else if (m_scale_size.second != WindowHeightDefault) { // 说明是偏方形屏
|
||||
// if (rect.height <= WindowHeightDefault / 2) {
|
||||
// if (rect.y + rect.height <= WindowHeightDefault / 2) { // 整个矩形都在上半边
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second / 2;
|
||||
// }
|
||||
// else if (rect.y >= WindowHeightDefault / 2) { // 整个矩形都在下半边
|
||||
// dst.y = m_scale_size.second / 2;
|
||||
// dst.height = m_scale_size.second / 2; // 整个矩形横跨了中线
|
||||
// }
|
||||
// else {
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// else {
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second;
|
||||
// }
|
||||
// }
|
||||
// return dst;
|
||||
//}
|
||||
// else {
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second;
|
||||
// }
|
||||
// }
|
||||
// return dst;
|
||||
// }
|
||||
|
||||
std::pair<int, int> asst::Controller::get_scale_size() const noexcept
|
||||
{
|
||||
@@ -232,7 +223,7 @@ void asst::Controller::pipe_working_proc()
|
||||
call_command(cmd);
|
||||
++m_completed_id;
|
||||
}
|
||||
//else if (!m_thread_idle) { // 队列中没有任务,又不是闲置的时候,就去截图
|
||||
// else if (!m_thread_idle) { // 队列中没有任务,又不是闲置的时候,就去截图
|
||||
// cmd_queue_lock.unlock();
|
||||
// auto start_time = std::chrono::steady_clock::now();
|
||||
// screencap();
|
||||
@@ -243,15 +234,16 @@ void asst::Controller::pipe_working_proc()
|
||||
// m_cmd_condvar.wait_until(
|
||||
// cmd_queue_lock,
|
||||
// start_time + std::chrono::milliseconds(1000)); // todo 时间写到配置文件里
|
||||
//}
|
||||
// }
|
||||
else {
|
||||
//m_cmd_condvar.wait(cmd_queue_lock, [&]() -> bool {return !m_thread_idle; });
|
||||
// m_cmd_condvar.wait(cmd_queue_lock, [&]() -> bool {return !m_thread_idle; });
|
||||
m_cmd_condvar.wait(cmd_queue_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::vector<uchar>> 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)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
LogTraceScope(std::string(__FUNCTION__) + " | `" + cmd + "`");
|
||||
@@ -260,19 +252,19 @@ std::optional<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
auto check_timeout = [&]() -> bool {
|
||||
return timeout &&
|
||||
timeout < std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start_time)
|
||||
.count();
|
||||
return timeout && timeout < std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start_time)
|
||||
.count();
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_START
|
||||
PROCESS_INFORMATION process_info = { nullptr }; // 进程信息结构体
|
||||
PROCESS_INFORMATION process_info = { nullptr }; // 进程信息结构体
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_END
|
||||
|
||||
BOOL create_ret = CreateProcessA(nullptr, const_cast<LPSTR>(cmd.c_str()), nullptr, nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr, &m_child_startup_info, &process_info);
|
||||
BOOL create_ret = CreateProcessA(nullptr, const_cast<LPSTR>(cmd.c_str()), nullptr, nullptr, TRUE, CREATE_NO_WINDOW,
|
||||
nullptr, nullptr, &m_child_startup_info, &process_info);
|
||||
if (!create_ret) {
|
||||
Log.error("Call `", cmd, "` create process failed, ret", create_ret);
|
||||
return std::nullopt;
|
||||
@@ -282,8 +274,8 @@ std::optional<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
DWORD read_num = 0;
|
||||
std::unique_lock<std::mutex> pipe_lock(m_pipe_mutex);
|
||||
do {
|
||||
//DWORD write_num = 0;
|
||||
//WriteFile(parent_write, cmd.c_str(), cmd.size(), &write_num, nullptr);
|
||||
// DWORD write_num = 0;
|
||||
// WriteFile(parent_write, cmd.c_str(), cmd.size(), &write_num, nullptr);
|
||||
while (PeekNamedPipe(m_pipe_read, nullptr, 0, nullptr, &peek_num, nullptr) && peek_num > 0) {
|
||||
if (ReadFile(m_pipe_read, m_pipe_buffer.get(), PipeBuffSize, &read_num, nullptr)) {
|
||||
pipe_data.insert(pipe_data.end(), m_pipe_buffer.get(), m_pipe_buffer.get() + read_num);
|
||||
@@ -300,7 +292,8 @@ std::optional<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
select(static_cast<int>(m_server_sock) + 1, &fdset, nullptr, nullptr, &select_timeout);
|
||||
if (FD_ISSET(m_server_sock, &fdset)) {
|
||||
SOCKET client_sock = ::accept(m_server_sock, nullptr, nullptr);
|
||||
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&TimeoutMilliseconds), sizeof(int));
|
||||
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&TimeoutMilliseconds),
|
||||
sizeof(int));
|
||||
int recv_size = 0;
|
||||
do {
|
||||
recv_size = ::recv(client_sock, (char*)m_socket_buffer.get(), SocketBuffSize, NULL);
|
||||
@@ -372,14 +365,11 @@ std::optional<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
m_inited = false;
|
||||
|
||||
// 之前可以运行,突然运行不了了,这种情况多半是 adb 炸了。所以重新连接一下
|
||||
json::value reconnect_info = json::object{
|
||||
{ "uuid", m_uuid},
|
||||
{ "what", "Reconnecting" },
|
||||
{ "why", "" },
|
||||
{ "details", json::object {
|
||||
{ "reconnect", m_adb.connect },
|
||||
{ "cmd", cmd }
|
||||
}} };
|
||||
json::value reconnect_info =
|
||||
json::object { { "uuid", m_uuid },
|
||||
{ "what", "Reconnecting" },
|
||||
{ "why", "" },
|
||||
{ "details", json::object { { "reconnect", m_adb.connect }, { "cmd", cmd } } } };
|
||||
constexpr static int ReconnectTimes = 20;
|
||||
for (int i = 0; i < ReconnectTimes; ++i) {
|
||||
if (need_exit()) {
|
||||
@@ -393,9 +383,8 @@ std::optional<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
bool is_reconnect_success = false;
|
||||
if (reconnect_ret) {
|
||||
auto& reconnect_val = reconnect_ret.value();
|
||||
std::string reconnect_str(
|
||||
std::make_move_iterator(reconnect_val.begin()),
|
||||
std::make_move_iterator(reconnect_val.end()));
|
||||
std::string reconnect_str(std::make_move_iterator(reconnect_val.begin()),
|
||||
std::make_move_iterator(reconnect_val.end()));
|
||||
is_reconnect_success = reconnect_str.find("error") == std::string::npos;
|
||||
}
|
||||
if (is_reconnect_success) {
|
||||
@@ -410,13 +399,10 @@ std::optional<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
}
|
||||
}
|
||||
}
|
||||
json::value info = json::object{
|
||||
{ "uuid", m_uuid},
|
||||
{ "what", "Disconnect" },
|
||||
{ "why", "Reconnect failed" },
|
||||
{ "details", json::object {
|
||||
{ "cmd", m_adb.connect }
|
||||
}} };
|
||||
json::value info = json::object { { "uuid", m_uuid },
|
||||
{ "what", "Disconnect" },
|
||||
{ "why", "Reconnect failed" },
|
||||
{ "details", json::object { { "cmd", m_adb.connect } } } };
|
||||
m_inited = false;
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
}
|
||||
@@ -431,9 +417,7 @@ void asst::Controller::convert_lf(std::vector<uchar>& data)
|
||||
if (data.empty() || data.size() < 2) {
|
||||
return;
|
||||
}
|
||||
auto pred = [](const std::vector<uchar>::iterator& cur) -> bool {
|
||||
return *cur == '\r' && *(cur + 1) == '\n';
|
||||
};
|
||||
auto pred = [](const std::vector<uchar>::iterator& cur) -> bool { return *cur == '\r' && *(cur + 1) == '\n'; };
|
||||
// find the first of "\r\n"
|
||||
auto first_iter = data.end();
|
||||
for (auto iter = data.begin(); iter != data.end() - 1; ++iter) {
|
||||
@@ -487,10 +471,8 @@ 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(std::random_device{}());
|
||||
static std::uniform_int_distribution<unsigned> rand_uni(
|
||||
opt.control_delay_lower,
|
||||
opt.control_delay_upper);
|
||||
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);
|
||||
|
||||
unsigned rand_delay = rand_uni(rand_engine);
|
||||
|
||||
@@ -528,7 +510,8 @@ int asst::Controller::push_cmd(const std::string& cmd)
|
||||
return static_cast<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)
|
||||
std::optional<unsigned short> asst::Controller::try_to_init_socket(const std::string& local_address,
|
||||
unsigned short try_port, unsigned short try_times)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -589,12 +572,12 @@ bool asst::Controller::screencap()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
//if (true) {
|
||||
// m_inited = true;
|
||||
// std::unique_lock<std::shared_mutex> image_lock(m_image_mutex);
|
||||
// m_cache_image = cv::imread("err/1.png");
|
||||
// return true;
|
||||
//}
|
||||
// if (true) {
|
||||
// m_inited = true;
|
||||
// std::unique_lock<std::shared_mutex> image_lock(m_image_mutex);
|
||||
// m_cache_image = cv::imread("err/1.png");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
DecodeFunc decode_raw = [&](std::vector<uchar>& data) -> bool {
|
||||
if (data.empty()) {
|
||||
@@ -605,8 +588,7 @@ bool asst::Controller::screencap()
|
||||
return false;
|
||||
}
|
||||
size_t header_size = data.size() - std_size;
|
||||
bool is_all_zero =
|
||||
std::all_of(data.data() + header_size, data.data() + std_size, std::logical_not<bool>{});
|
||||
bool is_all_zero = std::all_of(data.data() + header_size, data.data() + std_size, std::logical_not<bool> {});
|
||||
if (is_all_zero) {
|
||||
return false;
|
||||
}
|
||||
@@ -631,7 +613,7 @@ bool asst::Controller::screencap()
|
||||
}
|
||||
size_t header_size = unzip_data.size() - std_size;
|
||||
bool is_all_zero =
|
||||
std::all_of(unzip_data.data() + header_size, unzip_data.data() + std_size, std::logical_not<bool>{});
|
||||
std::all_of(unzip_data.data() + header_size, unzip_data.data() + std_size, std::logical_not<bool> {});
|
||||
if (is_all_zero) {
|
||||
return false;
|
||||
}
|
||||
@@ -656,15 +638,13 @@ bool asst::Controller::screencap()
|
||||
};
|
||||
|
||||
switch (m_adb.screencap_method) {
|
||||
case AdbProperty::ScreencapMethod::UnknownYet:
|
||||
{
|
||||
case AdbProperty::ScreencapMethod::UnknownYet: {
|
||||
Log.info("Try to find the fastest way to screencap");
|
||||
m_inited = false;
|
||||
auto min_cost = std::chrono::nanoseconds(LLONG_MAX);
|
||||
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
if (m_support_socket && m_server_started &&
|
||||
screencap(m_adb.screencap_raw_by_nc, decode_raw, true)) {
|
||||
if (m_support_socket && m_server_started && screencap(m_adb.screencap_raw_by_nc, decode_raw, true)) {
|
||||
auto duration = std::chrono::high_resolution_clock::now() - start_time;
|
||||
if (duration < min_cost) {
|
||||
m_adb.screencap_method = AdbProperty::ScreencapMethod::RawByNc;
|
||||
@@ -709,23 +689,16 @@ bool asst::Controller::screencap()
|
||||
Log.info("The fastest way is", static_cast<int>(m_adb.screencap_method), ", cost:", min_cost.count(), "ns");
|
||||
clear_lf_info();
|
||||
return m_inited;
|
||||
}
|
||||
break;
|
||||
case AdbProperty::ScreencapMethod::RawByNc:
|
||||
{
|
||||
} break;
|
||||
case AdbProperty::ScreencapMethod::RawByNc: {
|
||||
return screencap(m_adb.screencap_raw_by_nc, decode_raw, true);
|
||||
}
|
||||
break;
|
||||
case AdbProperty::ScreencapMethod::RawWithGzip:
|
||||
{
|
||||
} break;
|
||||
case AdbProperty::ScreencapMethod::RawWithGzip: {
|
||||
return screencap(m_adb.screencap_raw_with_gzip, decode_raw_with_gzip);
|
||||
}
|
||||
break;
|
||||
case AdbProperty::ScreencapMethod::Encode:
|
||||
{
|
||||
} break;
|
||||
case AdbProperty::ScreencapMethod::Encode: {
|
||||
return screencap(m_adb.screencap_encode, decode_encode);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -825,7 +798,7 @@ int asst::Controller::click(const Point& p, bool block)
|
||||
{
|
||||
int x = static_cast<int>(p.x * m_control_scale);
|
||||
int y = static_cast<int>(p.y * m_control_scale);
|
||||
//log.trace("Click, raw:", p.x, p.y, "corr:", x, y);
|
||||
// log.trace("Click, raw:", p.x, p.y, "corr:", x, y);
|
||||
|
||||
return click_without_scale(Point(x, y), block);
|
||||
}
|
||||
@@ -840,10 +813,8 @@ int asst::Controller::click_without_scale(const Point& p, bool block)
|
||||
if (p.x < 0 || p.x >= m_width || p.y < 0 || p.y >= m_height) {
|
||||
Log.error("click point out of range");
|
||||
}
|
||||
std::string cur_cmd = utils::string_replace_all_batch(m_adb.click, {
|
||||
{ "[x]", std::to_string(p.x) },
|
||||
{ "[y]", std::to_string(p.y) }
|
||||
});
|
||||
std::string cur_cmd = utils::string_replace_all_batch(
|
||||
m_adb.click, { { "[x]", std::to_string(p.x) }, { "[y]", std::to_string(p.y) } });
|
||||
int id = push_cmd(cur_cmd);
|
||||
if (block) {
|
||||
wait(id);
|
||||
@@ -856,13 +827,14 @@ int asst::Controller::click_without_scale(const Rect& rect, bool block)
|
||||
return click_without_scale(rand_point_in_rect(rect), block);
|
||||
}
|
||||
|
||||
int asst::Controller::swipe(const Point& p1, const Point& p2, int duration, bool block, int extra_delay, bool extra_swipe)
|
||||
int asst::Controller::swipe(const Point& p1, const Point& p2, int duration, bool block, int extra_delay,
|
||||
bool extra_swipe)
|
||||
{
|
||||
int x1 = static_cast<int>(p1.x * m_control_scale);
|
||||
int y1 = static_cast<int>(p1.y * m_control_scale);
|
||||
int x2 = static_cast<int>(p2.x * m_control_scale);
|
||||
int y2 = static_cast<int>(p2.y * m_control_scale);
|
||||
//log.trace("Swipe, raw:", p1.x, p1.y, p2.x, p2.y, "corr:", x1, y1, x2, y2);
|
||||
// log.trace("Swipe, raw:", p1.x, p1.y, p2.x, p2.y, "corr:", x1, y1, x2, y2);
|
||||
|
||||
return swipe_without_scale(Point(x1, y1), Point(x2, y2), duration, block, extra_delay, extra_swipe);
|
||||
}
|
||||
@@ -872,7 +844,8 @@ int asst::Controller::swipe(const Rect& r1, const Rect& r2, int duration, bool b
|
||||
return swipe(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay, extra_swipe);
|
||||
}
|
||||
|
||||
int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool block, int extra_delay, bool extra_swipe)
|
||||
int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool block, int extra_delay,
|
||||
bool extra_swipe)
|
||||
{
|
||||
int x1 = p1.x;
|
||||
int y1 = p1.y;
|
||||
@@ -886,25 +859,25 @@ int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int
|
||||
y1 = std::clamp(y1, 0, m_height - 1);
|
||||
}
|
||||
|
||||
std::string cur_cmd = utils::string_replace_all_batch(m_adb.swipe, {
|
||||
{ "[x1]", std::to_string(x1) },
|
||||
{ "[y1]", std::to_string(y1) },
|
||||
{ "[x2]", std::to_string(x2) },
|
||||
{ "[y2]", std::to_string(y2) },
|
||||
{ "[duration]", duration <= 0 ? "" : std::to_string(duration) }
|
||||
});
|
||||
std::string cur_cmd = utils::string_replace_all_batch(
|
||||
m_adb.swipe, { { "[x1]", std::to_string(x1) },
|
||||
{ "[y1]", std::to_string(y1) },
|
||||
{ "[x2]", std::to_string(x2) },
|
||||
{ "[y2]", std::to_string(y2) },
|
||||
{ "[duration]", duration <= 0 ? "" : std::to_string(duration) } });
|
||||
|
||||
int id = 0;
|
||||
// 额外的滑动:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来
|
||||
const auto& opt = Resrc.cfg().get_options();
|
||||
if (extra_swipe && opt.adb_extra_swipe_duration > 0) {
|
||||
std::string extra_cmd = utils::string_replace_all_batch(m_adb.swipe, {
|
||||
{ "[x1]", std::to_string(x2)},
|
||||
{ "[y1]", std::to_string(y2) },
|
||||
{ "[x2]", std::to_string(x2) },
|
||||
{ "[y2]", std::to_string(y2 - opt.adb_extra_swipe_dist /* * m_control_scale*/) },
|
||||
{ "[duration]", std::to_string(opt.adb_extra_swipe_duration) },
|
||||
});
|
||||
std::string extra_cmd = utils::string_replace_all_batch(
|
||||
m_adb.swipe, {
|
||||
{ "[x1]", std::to_string(x2) },
|
||||
{ "[y1]", std::to_string(y2) },
|
||||
{ "[x2]", std::to_string(x2) },
|
||||
{ "[y2]", std::to_string(y2 - opt.adb_extra_swipe_dist /* * m_control_scale*/) },
|
||||
{ "[duration]", std::to_string(opt.adb_extra_swipe_duration) },
|
||||
});
|
||||
push_cmd(cur_cmd);
|
||||
id = push_cmd(extra_cmd);
|
||||
}
|
||||
@@ -919,9 +892,11 @@ int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int
|
||||
return id;
|
||||
}
|
||||
|
||||
int asst::Controller::swipe_without_scale(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay, bool extra_swipe)
|
||||
int asst::Controller::swipe_without_scale(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay,
|
||||
bool extra_swipe)
|
||||
{
|
||||
return swipe_without_scale(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay, extra_swipe);
|
||||
return swipe_without_scale(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay,
|
||||
extra_swipe);
|
||||
}
|
||||
|
||||
bool asst::Controller::connect(const std::string& adb_path, const std::string& address, const std::string& config)
|
||||
@@ -938,22 +913,14 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
#endif
|
||||
|
||||
auto get_info_json = [&]() -> json::value {
|
||||
return json::object{
|
||||
{ "uuid", m_uuid},
|
||||
{ "details", json::object {
|
||||
{ "adb", adb_path },
|
||||
{ "address", address },
|
||||
{ "config", config }
|
||||
}}
|
||||
};
|
||||
return json::object { { "uuid", m_uuid },
|
||||
{ "details",
|
||||
json::object { { "adb", adb_path }, { "address", address }, { "config", config } } } };
|
||||
};
|
||||
|
||||
auto adb_ret = Resrc.cfg().get_adb_cfg(config);
|
||||
if (!adb_ret) {
|
||||
json::value info = get_info_json() |
|
||||
json::object{
|
||||
{ "what", "ConnectFailed" },
|
||||
{ "why", "ConfigNotFound" } };
|
||||
json::value info = get_info_json() | json::object { { "what", "ConnectFailed" }, { "why", "ConfigNotFound" } };
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
@@ -966,12 +933,12 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
// 里面的值每次执行命令后可能更新,所以要用 lambda 拿最新的
|
||||
auto cmd_replace = [&](const std::string& cfg_cmd) -> std::string {
|
||||
return utils::string_replace_all_batch(cfg_cmd, {
|
||||
{ "[Adb]", adb_path },
|
||||
{ "[AdbSerial]", address },
|
||||
{ "[DisplayId]", display_id },
|
||||
{ "[NcPort]", std::to_string(nc_port) },
|
||||
{ "[NcAddress]", nc_address },
|
||||
});
|
||||
{ "[Adb]", adb_path },
|
||||
{ "[AdbSerial]", address },
|
||||
{ "[DisplayId]", display_id },
|
||||
{ "[NcPort]", std::to_string(nc_port) },
|
||||
{ "[NcAddress]", nc_address },
|
||||
});
|
||||
};
|
||||
|
||||
/* connect */
|
||||
@@ -982,17 +949,13 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
bool is_connect_success = false;
|
||||
if (connect_ret) {
|
||||
auto& connect_val = connect_ret.value();
|
||||
std::string connect_str(
|
||||
std::make_move_iterator(connect_val.begin()),
|
||||
std::make_move_iterator(connect_val.end()));
|
||||
std::string connect_str(std::make_move_iterator(connect_val.begin()),
|
||||
std::make_move_iterator(connect_val.end()));
|
||||
is_connect_success = connect_str.find("error") == std::string::npos;
|
||||
}
|
||||
if (!is_connect_success) {
|
||||
json::value info = get_info_json() |
|
||||
json::object{
|
||||
{ "what", "ConnectFailed" },
|
||||
{ "why", "Connection command failed to exec" }
|
||||
};
|
||||
json::value info = get_info_json() | json::object { { "what", "ConnectFailed" },
|
||||
{ "why", "Connection command failed to exec" } };
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
@@ -1003,26 +966,17 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
auto uuid_ret = call_command(cmd_replace(adb_cfg.uuid));
|
||||
if (!uuid_ret) {
|
||||
json::value info = get_info_json() |
|
||||
json::object{
|
||||
{ "what", "ConnectFailed" },
|
||||
{ "why", "Uuid command failed to exec" }
|
||||
};
|
||||
json::object { { "what", "ConnectFailed" }, { "why", "Uuid command failed to exec" } };
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& uuid_result = uuid_ret.value();
|
||||
std::string uuid_str(
|
||||
std::make_move_iterator(uuid_result.begin()),
|
||||
std::make_move_iterator(uuid_result.end()));
|
||||
std::string uuid_str(std::make_move_iterator(uuid_result.begin()), std::make_move_iterator(uuid_result.end()));
|
||||
std::erase(uuid_str, ' ');
|
||||
m_uuid = std::move(uuid_str);
|
||||
|
||||
json::value info = get_info_json() |
|
||||
json::object{
|
||||
{ "what", "UuidGot" },
|
||||
{ "why", "" }
|
||||
};
|
||||
json::value info = get_info_json() | json::object { { "what", "UuidGot" }, { "why", "" } };
|
||||
info["details"]["uuid"] = m_uuid;
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
}
|
||||
@@ -1036,9 +990,8 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
|
||||
auto& display_id_result = display_id_ret.value();
|
||||
convert_lf(display_id_result);
|
||||
std::string display_id_pipe_str(
|
||||
std::make_move_iterator(display_id_result.begin()),
|
||||
std::make_move_iterator(display_id_result.end()));
|
||||
std::string display_id_pipe_str(std::make_move_iterator(display_id_result.begin()),
|
||||
std::make_move_iterator(display_id_result.end()));
|
||||
auto last = display_id_pipe_str.rfind(':');
|
||||
if (last == std::string::npos) {
|
||||
return false;
|
||||
@@ -1053,19 +1006,15 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
{
|
||||
auto display_ret = call_command(cmd_replace(adb_cfg.display));
|
||||
if (!display_ret) {
|
||||
json::value info = get_info_json() |
|
||||
json::object{
|
||||
{ "what", "ConnectFailed" },
|
||||
{ "why", "Display command failed to exec" }
|
||||
};
|
||||
json::value info = get_info_json() | json::object { { "what", "ConnectFailed" },
|
||||
{ "why", "Display command failed to exec" } };
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& display_result = display_ret.value();
|
||||
std::string display_pipe_str(
|
||||
std::make_move_iterator(display_result.begin()),
|
||||
std::make_move_iterator(display_result.end()));
|
||||
std::string display_pipe_str(std::make_move_iterator(display_result.begin()),
|
||||
std::make_move_iterator(display_result.end()));
|
||||
int size_value1 = 0;
|
||||
int size_value2 = 0;
|
||||
#ifdef _MSC_VER
|
||||
@@ -1078,16 +1027,9 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
m_width = (std::max)(size_value1, size_value2);
|
||||
m_height = (std::min)(size_value1, size_value2);
|
||||
|
||||
json::value info = get_info_json() |
|
||||
json::object{
|
||||
{ "what", "ResolutionGot" },
|
||||
{ "why", "" }
|
||||
};
|
||||
json::value info = get_info_json() | json::object { { "what", "ResolutionGot" }, { "why", "" } };
|
||||
|
||||
info["details"] |= json::object{
|
||||
{ "width", m_width },
|
||||
{ "height", m_height }
|
||||
};
|
||||
info["details"] |= json::object { { "width", m_width }, { "height", m_height } };
|
||||
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
|
||||
@@ -1103,8 +1045,8 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
else if (std::fabs(static_cast<double>(WindowWidthDefault) / static_cast<double>(WindowHeightDefault)
|
||||
- static_cast<double>(m_width) / static_cast<double>(m_height)) > 1e-7) {
|
||||
else if (std::fabs(static_cast<double>(WindowWidthDefault) / static_cast<double>(WindowHeightDefault) -
|
||||
static_cast<double>(m_width) / static_cast<double>(m_height)) > 1e-7) {
|
||||
info["what"] = "UnsupportedResolution";
|
||||
info["why"] = "Not 16:9";
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
@@ -1132,11 +1074,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
}
|
||||
|
||||
{
|
||||
json::value info = get_info_json() |
|
||||
json::object{
|
||||
{ "what", "Connected" },
|
||||
{ "why", "" }
|
||||
};
|
||||
json::value info = get_info_json() | json::object { { "what", "Connected" }, { "why", "" } };
|
||||
m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg);
|
||||
}
|
||||
|
||||
@@ -1150,8 +1088,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
|
||||
if (m_support_socket && !m_server_started) {
|
||||
std::string bind_address;
|
||||
if (size_t pos = address.rfind(':');
|
||||
pos != std::string::npos) {
|
||||
if (size_t pos = address.rfind(':'); pos != std::string::npos) {
|
||||
bind_address = address.substr(0, pos);
|
||||
}
|
||||
else {
|
||||
@@ -1159,15 +1096,14 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
|
||||
}
|
||||
|
||||
// Todo: detect remote address, and check remote port
|
||||
// reference from https://github.com/ArknightsAutoHelper/ArknightsAutoHelper/blob/master/automator/connector/ADBConnector.py#L436
|
||||
// reference from
|
||||
// https://github.com/ArknightsAutoHelper/ArknightsAutoHelper/blob/master/automator/connector/ADBConnector.py#L436
|
||||
auto nc_address_ret = call_command(cmd_replace(adb_cfg.nc_address));
|
||||
if (nc_address_ret) {
|
||||
auto& nc_result = nc_address_ret.value();
|
||||
std::string nc_result_str(
|
||||
std::make_move_iterator(nc_result.begin()),
|
||||
std::make_move_iterator(nc_result.end()));
|
||||
if (auto pos = nc_result_str.find(' ');
|
||||
pos != std::string::npos) {
|
||||
std::string nc_result_str(std::make_move_iterator(nc_result.begin()),
|
||||
std::make_move_iterator(nc_result.end()));
|
||||
if (auto pos = nc_result_str.find(' '); pos != std::string::npos) {
|
||||
nc_address = nc_result_str.substr(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
#include "AsstConf.h"
|
||||
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <random>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
#include "NoWarningCVMat.h"
|
||||
|
||||
#include "AsstTypes.h"
|
||||
#include "AsstMsg.h"
|
||||
#include "AsstTypes.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
@@ -52,15 +52,19 @@ namespace asst
|
||||
int click_without_scale(const Rect& rect, bool block = true);
|
||||
|
||||
constexpr static int SwipeExtraDelayDefault = 1000;
|
||||
int swipe(const Point& p1, const Point& p2, int duration = 0, bool block = true, int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
int swipe(const Rect& r1, const Rect& r2, int duration = 0, bool block = true, int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
int swipe_without_scale(const Point& p1, const Point& p2, int duration = 0, bool block = true, int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
int swipe_without_scale(const Rect& r1, const Rect& r2, int duration = 0, bool block = true, int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
int swipe(const Point& p1, const Point& p2, int duration = 0, bool block = true,
|
||||
int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
int swipe(const Rect& r1, const Rect& r2, int duration = 0, bool block = true,
|
||||
int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
int swipe_without_scale(const Point& p1, const Point& p2, int duration = 0, bool block = true,
|
||||
int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
int swipe_without_scale(const Rect& r1, const Rect& r2, int duration = 0, bool block = true,
|
||||
int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
|
||||
|
||||
void wait(unsigned id) const noexcept;
|
||||
|
||||
// 异形屏矫正
|
||||
//Rect shaped_correct(const Rect& rect) const;
|
||||
// Rect shaped_correct(const Rect& rect) const;
|
||||
std::pair<int, int> get_scale_size() const noexcept;
|
||||
|
||||
Controller& operator=(const Controller&) = delete;
|
||||
@@ -69,10 +73,12 @@ namespace asst
|
||||
private:
|
||||
bool need_exit() const;
|
||||
void pipe_working_proc();
|
||||
std::optional<std::vector<uchar>> 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);
|
||||
std::optional<unsigned short> try_to_init_socket(const std::string& local_address, unsigned short try_port,
|
||||
unsigned short try_times = 10U);
|
||||
|
||||
using DecodeFunc = std::function<bool(std::vector<uchar>&)>;
|
||||
bool screencap();
|
||||
@@ -94,20 +100,20 @@ namespace asst
|
||||
|
||||
std::minstd_rand m_rand_engine;
|
||||
|
||||
constexpr static int PipeBuffSize = 4 * 1024 * 1024; // 管道缓冲区大小
|
||||
constexpr static int SocketBuffSize = 4 * 1024 * 1024; // socket 缓冲区大小
|
||||
constexpr static int PipeBuffSize = 4 * 1024 * 1024; // 管道缓冲区大小
|
||||
constexpr static int SocketBuffSize = 4 * 1024 * 1024; // socket 缓冲区大小
|
||||
std::unique_ptr<uchar[]> m_pipe_buffer = nullptr;
|
||||
std::mutex m_pipe_mutex;
|
||||
std::unique_ptr<char[]> m_socket_buffer = nullptr;
|
||||
std::mutex m_socket_mutex;
|
||||
#ifdef _WIN32
|
||||
HANDLE m_pipe_read = nullptr; // 读管道句柄
|
||||
HANDLE m_pipe_write = nullptr; // 写管道句柄
|
||||
HANDLE m_pipe_child_read = nullptr; // 子进程的读管道句柄
|
||||
HANDLE m_pipe_child_write = nullptr; // 子进程的写管道句柄
|
||||
HANDLE m_pipe_read = nullptr; // 读管道句柄
|
||||
HANDLE m_pipe_write = nullptr; // 写管道句柄
|
||||
HANDLE m_pipe_child_read = nullptr; // 子进程的读管道句柄
|
||||
HANDLE m_pipe_child_write = nullptr; // 子进程的写管道句柄
|
||||
|
||||
ASST_AUTO_DEDUCED_ZERO_INIT_START
|
||||
SECURITY_ATTRIBUTES m_pipe_sec_attr = { 0 }; // 管道安全描述符
|
||||
SECURITY_ATTRIBUTES m_pipe_sec_attr = { 0 }; // 管道安全描述符
|
||||
STARTUPINFOA m_child_startup_info = { 0 }; // 子进程启动信息
|
||||
|
||||
WSADATA m_wsa_data = { 0 };
|
||||
@@ -150,7 +156,7 @@ namespace asst
|
||||
enum class ScreencapMethod
|
||||
{
|
||||
UnknownYet,
|
||||
//Default,
|
||||
// Default,
|
||||
RawByNc,
|
||||
RawWithGzip,
|
||||
Encode
|
||||
@@ -172,7 +178,7 @@ namespace asst
|
||||
cv::Mat m_cache_image;
|
||||
|
||||
bool m_thread_exit = false;
|
||||
//bool m_thread_idle = true;
|
||||
// bool m_thread_idle = true;
|
||||
std::mutex m_cmd_queue_mutex;
|
||||
std::condition_variable m_cmd_condvar;
|
||||
std::queue<std::string> m_cmd_queue;
|
||||
@@ -180,4 +186,4 @@ namespace asst
|
||||
unsigned m_push_id = 0; // push_id的自增总是伴随着queue的push,肯定是要上锁的,所以没必要原子
|
||||
std::thread m_cmd_thread;
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -39,7 +39,7 @@ bool asst::CopilotConfiger::parse(const json::value& json)
|
||||
// 单个干员的,干员名直接作为组名
|
||||
std::string group_name = oper.name;
|
||||
|
||||
battle_actions.groups.emplace(std::move(group_name), std::vector{ std::move(oper) });
|
||||
battle_actions.groups.emplace(std::move(group_name), std::vector { std::move(oper) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,8 +96,7 @@ bool asst::CopilotConfiger::parse(const json::value& json)
|
||||
|
||||
std::string type_str = action_info.get("type", "Deploy");
|
||||
|
||||
if (auto iter = ActionTypeMapping.find(type_str);
|
||||
iter != ActionTypeMapping.end()) {
|
||||
if (auto iter = ActionTypeMapping.find(type_str); iter != ActionTypeMapping.end()) {
|
||||
action.type = iter->second;
|
||||
}
|
||||
else {
|
||||
@@ -111,36 +110,25 @@ bool asst::CopilotConfiger::parse(const json::value& json)
|
||||
action.location.y = action_info.get("location", 1, 0);
|
||||
|
||||
static const std::unordered_map<std::string, BattleDeployDirection> DeployDirectionMapping = {
|
||||
{ "Right", BattleDeployDirection::Right },
|
||||
{ "RIGHT", BattleDeployDirection::Right },
|
||||
{ "right", BattleDeployDirection::Right },
|
||||
{ "右", BattleDeployDirection::Right },
|
||||
{ "Right", BattleDeployDirection::Right }, { "RIGHT", BattleDeployDirection::Right },
|
||||
{ "right", BattleDeployDirection::Right }, { "右", BattleDeployDirection::Right },
|
||||
|
||||
{ "Left", BattleDeployDirection::Left },
|
||||
{ "LEFT", BattleDeployDirection::Left },
|
||||
{ "left", BattleDeployDirection::Left },
|
||||
{ "左", BattleDeployDirection::Left },
|
||||
{ "Left", BattleDeployDirection::Left }, { "LEFT", BattleDeployDirection::Left },
|
||||
{ "left", BattleDeployDirection::Left }, { "左", BattleDeployDirection::Left },
|
||||
|
||||
{ "Up", BattleDeployDirection::Up },
|
||||
{ "UP", BattleDeployDirection::Up },
|
||||
{ "up", BattleDeployDirection::Up },
|
||||
{ "上", BattleDeployDirection::Up },
|
||||
{ "Up", BattleDeployDirection::Up }, { "UP", BattleDeployDirection::Up },
|
||||
{ "up", BattleDeployDirection::Up }, { "上", BattleDeployDirection::Up },
|
||||
|
||||
{ "Down", BattleDeployDirection::Down },
|
||||
{ "DOWN", BattleDeployDirection::Down },
|
||||
{ "down", BattleDeployDirection::Down },
|
||||
{ "下", BattleDeployDirection::Down },
|
||||
{ "Down", BattleDeployDirection::Down }, { "DOWN", BattleDeployDirection::Down },
|
||||
{ "down", BattleDeployDirection::Down }, { "下", BattleDeployDirection::Down },
|
||||
|
||||
{ "None", BattleDeployDirection::None },
|
||||
{ "NONE", BattleDeployDirection::None },
|
||||
{ "none", BattleDeployDirection::None },
|
||||
{ "无", BattleDeployDirection::None },
|
||||
{ "None", BattleDeployDirection::None }, { "NONE", BattleDeployDirection::None },
|
||||
{ "none", BattleDeployDirection::None }, { "无", BattleDeployDirection::None },
|
||||
};
|
||||
|
||||
std::string direction_str = action_info.get("direction", "Right");
|
||||
|
||||
if (auto iter = DeployDirectionMapping.find(direction_str);
|
||||
iter != DeployDirectionMapping.end()) {
|
||||
if (auto iter = DeployDirectionMapping.find(direction_str); iter != DeployDirectionMapping.end()) {
|
||||
action.direction = iter->second;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -14,10 +14,8 @@ namespace asst
|
||||
return m_battle_actions.contains(stage_name);
|
||||
}
|
||||
|
||||
auto get_actions(const std::string& stage_name) const noexcept
|
||||
{
|
||||
return m_battle_actions.at(stage_name);
|
||||
}
|
||||
auto get_actions(const std::string& stage_name) const noexcept { return m_battle_actions.at(stage_name); }
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
std::unordered_map<std::string, BattleCopilotData> m_battle_actions;
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
#include "CopilotTask.h"
|
||||
|
||||
#include "Resource.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "BattleProcessTask.h"
|
||||
#include "BattleFormationTask.h"
|
||||
#include "BattleProcessTask.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "Resource.h"
|
||||
|
||||
asst::CopilotTask::CopilotTask(const AsstCallback& callback, void* callback_arg)
|
||||
: PackageTask(callback, callback_arg, TaskType),
|
||||
m_formation_task_ptr(std::make_shared<BattleFormationTask>(callback, callback_arg, TaskType)),
|
||||
m_battle_task_ptr(std::make_shared<BattleProcessTask>(callback, callback_arg, TaskType))
|
||||
m_formation_task_ptr(std::make_shared<BattleFormationTask>(callback, callback_arg, TaskType)),
|
||||
m_battle_task_ptr(std::make_shared<BattleProcessTask>(callback, callback_arg, TaskType))
|
||||
{
|
||||
auto start_1_tp = std::make_shared<ProcessTask>(callback, callback_arg, TaskType);
|
||||
start_1_tp->set_tasks({ "BattleStartPre" })
|
||||
.set_retry_times(0)
|
||||
.set_ignore_error(true);
|
||||
start_1_tp->set_tasks({ "BattleStartPre" }).set_retry_times(0).set_ignore_error(true);
|
||||
m_subtasks.emplace_back(start_1_tp);
|
||||
|
||||
m_subtasks.emplace_back(m_formation_task_ptr)->set_ignore_error(false).set_retry_times(0);
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
#include "NoWarningCV.h"
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "MultiMatchImageAnalyzer.h"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
#include "AsstUtils.hpp"
|
||||
|
||||
void asst::CreditShopImageAnalyzer::set_black_list(std::vector<std::string> black_list)
|
||||
{
|
||||
@@ -87,11 +87,13 @@ bool asst::CreditShopImageAnalyzer::whether_to_buy_analyze()
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(m_image_draw, utils::make_rect<cv::Rect>(commodity), cv::Scalar(0, 0, 255), 2);
|
||||
#endif
|
||||
m_need_to_buy.emplace_back(commodity, ocr_analyzer.get_result().empty() ? std::string() : ocr_analyzer.get_result().front().text);
|
||||
m_need_to_buy.emplace_back(
|
||||
commodity, ocr_analyzer.get_result().empty() ? std::string() : ocr_analyzer.get_result().front().text);
|
||||
}
|
||||
|
||||
if (m_is_white_list) {
|
||||
ranges::sort(m_need_to_buy, std::less{}, [&](const auto& pair) { return ranges::find(m_shopping_list, pair.second); });
|
||||
ranges::sort(m_need_to_buy, std::less {},
|
||||
[&](const auto& pair) { return ranges::find(m_shopping_list, pair.second); });
|
||||
}
|
||||
|
||||
return !m_need_to_buy.empty();
|
||||
|
||||
@@ -14,10 +14,7 @@ namespace asst
|
||||
void set_black_list(std::vector<std::string> black_list);
|
||||
void set_white_list(std::vector<std::string> white_list);
|
||||
|
||||
const std::vector<Rect>& get_result() const noexcept
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
const std::vector<Rect>& get_result() const noexcept { return m_result; }
|
||||
|
||||
private:
|
||||
// 该分析器不支持外部设置ROI
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
|
||||
//#include "RoguelikeSkillSelectionTaskPlugin.h"
|
||||
|
||||
#include "StageDropsImageAnalyzer.h"
|
||||
#include "Logger.hpp"
|
||||
#include "StageDropsImageAnalyzer.h"
|
||||
|
||||
asst::DebugTask::DebugTask(const AsstCallback& callback, void* callback_arg)
|
||||
: PackageTask(callback, callback_arg, TaskType)
|
||||
{
|
||||
////auto task_ptr = std::make_shared<RoguelikeSkillSelectionTaskPlugin>(callback, callback_arg, TaskType);
|
||||
//auto task_ptr = std::make_shared<StageDropsTaskPlugin>(callback, callback_arg, TaskType);
|
||||
//m_subtasks.emplace_back(task_ptr);
|
||||
// auto task_ptr = std::make_shared<StageDropsTaskPlugin>(callback, callback_arg, TaskType);
|
||||
// m_subtasks.emplace_back(task_ptr);
|
||||
}
|
||||
|
||||
bool asst::DebugTask::run()
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "TaskData.h"
|
||||
#include "Resource.h"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "OcrWithPreprocessImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
#include "TaskData.h"
|
||||
|
||||
bool asst::DepotImageAnalyzer::analyze()
|
||||
{
|
||||
@@ -64,14 +64,15 @@ bool asst::DepotImageAnalyzer::analyze_base_rect()
|
||||
if (pos == NPos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& base_rect = base_item_info.rect;
|
||||
const auto& base_rect = base_item_info.rect;
|
||||
const auto& [base_x, base_y, base_w, base_h] = base_rect;
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(m_image_draw_resized, utils::make_rect<cv::Rect>(base_rect), cv::Scalar(0, 0, 255), 2);
|
||||
#endif
|
||||
|
||||
// 每个材料之间有间隔,这里 高度 * 2 的 roi, 一定有一个完整的材料 + 一个不完整的材料。所以识别结果只会有一个(除非这个间隔非常大)
|
||||
Rect vertical_rect(base_rect.x, base_rect.y + base_rect.height, base_rect.width, base_rect.height * 2);
|
||||
// 每个材料之间有间隔,这里 高度 * 2 的 roi, 一定有一个完整的材料 + 一个不完整的材料。
|
||||
// 所以识别结果只会有一个(除非这个间隔非常大)
|
||||
const Rect vertical_rect(base_x, base_y + base_h, base_w, base_h * 2);
|
||||
ItemInfo vertical_item_info;
|
||||
pos = match_item(vertical_rect, vertical_item_info, pos + 1);
|
||||
|
||||
@@ -80,20 +81,21 @@ bool asst::DepotImageAnalyzer::analyze_base_rect()
|
||||
#endif
|
||||
|
||||
// 宽度 * 2,同上
|
||||
Rect horizontal_roi(base_rect.x + base_rect.width, base_rect.y, base_rect.width * 2, base_rect.height);
|
||||
const Rect horizontal_roi(base_x + base_w, base_y, base_w * 2, base_h);
|
||||
ItemInfo horizontal_item_info;
|
||||
pos = match_item(horizontal_roi, horizontal_item_info, pos + 1);
|
||||
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(m_image_draw_resized, utils::make_rect<cv::Rect>(horizontal_item_info.rect), cv::Scalar(0, 0, 255), 2);
|
||||
cv::rectangle(m_image_draw_resized, utils::make_rect<cv::Rect>(horizontal_item_info.rect), cv::Scalar(0, 0, 255),
|
||||
2);
|
||||
#endif
|
||||
|
||||
int horizontal_spacing = horizontal_item_info.rect.x - (base_rect.x + base_rect.width);
|
||||
int vertical_spacing = vertical_item_info.rect.y - (base_rect.y + base_rect.height);
|
||||
const int horizontal_spacing = horizontal_item_info.rect.x - (base_x + base_w);
|
||||
const int vertical_spacing = vertical_item_info.rect.y - (base_y + base_h);
|
||||
|
||||
for (int x = base_rect.x; x <= m_image_resized.cols; x += (base_rect.width + horizontal_spacing)) {
|
||||
for (int y = base_rect.y; y <= m_image_resized.rows; y += (base_rect.height + vertical_spacing)) {
|
||||
Rect item_roi = Rect(x, y, base_rect.width, base_rect.height);
|
||||
for (int x = base_x; x <= m_image_resized.cols; x += (base_w + horizontal_spacing)) {
|
||||
for (int y = base_y; y <= m_image_resized.rows; y += (base_h + vertical_spacing)) {
|
||||
Rect item_roi = Rect(x, y, base_w, base_h);
|
||||
if (!m_resized_rect.include(item_roi)) {
|
||||
continue;
|
||||
}
|
||||
@@ -128,8 +130,10 @@ bool asst::DepotImageAnalyzer::analyze_all_items()
|
||||
info.quantity = match_quantity(info.rect);
|
||||
info.item_name = res_item.get_item_name(item_id);
|
||||
#ifdef ASST_DEBUG
|
||||
cv::putText(m_image_draw_resized, item_id, cv::Point(roi.x, roi.y - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2);
|
||||
cv::putText(m_image_draw_resized, std::to_string(info.quantity), cv::Point(roi.x, roi.y + 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2);
|
||||
cv::putText(m_image_draw_resized, item_id, cv::Point(roi.x, roi.y - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5,
|
||||
cv::Scalar(0, 0, 255), 2);
|
||||
cv::putText(m_image_draw_resized, std::to_string(info.quantity), cv::Point(roi.x, roi.y + 10),
|
||||
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2);
|
||||
#endif
|
||||
if (item_id.empty() || info.quantity == 0) {
|
||||
Log.error(__FUNCTION__, item_id, info.item_name, " quantity is zero");
|
||||
@@ -148,7 +152,8 @@ bool asst::DepotImageAnalyzer::check_roi_empty(const Rect& roi)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t asst::DepotImageAnalyzer::match_item(const Rect& roi, /* out */ ItemInfo& item_info, size_t begin_index, bool with_enlarge)
|
||||
size_t asst::DepotImageAnalyzer::match_item(const Rect& roi, /* out */ ItemInfo& item_info, size_t begin_index,
|
||||
bool with_enlarge)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -172,8 +177,7 @@ size_t asst::DepotImageAnalyzer::match_item(const Rect& roi, /* out */ ItemInfo&
|
||||
if (!analyzer.analyze()) {
|
||||
continue;
|
||||
}
|
||||
if (double score = analyzer.get_result().score;
|
||||
score >= matched.score) {
|
||||
if (double score = analyzer.get_result().score; score >= matched.score) {
|
||||
matched = analyzer.get_result();
|
||||
matched_item_id = item_id;
|
||||
matched_index = index;
|
||||
@@ -224,15 +228,14 @@ int asst::DepotImageAnalyzer::match_quantity(const Rect& roi)
|
||||
i_left = i;
|
||||
in = false;
|
||||
spacing = 0;
|
||||
contours.emplace_back(i_left, i_right + 1); // range 是前闭后开的
|
||||
contours.emplace_back(i_left, i_right + 1); // range 是前闭后开的
|
||||
}
|
||||
else if (!in && has_white) {
|
||||
i_right = i;
|
||||
in = true;
|
||||
}
|
||||
else if (!in) {
|
||||
if (++spacing > max_spacing &&
|
||||
i_left != 0) {
|
||||
if (++spacing > max_spacing && i_left != 0) {
|
||||
// filter out noise
|
||||
break;
|
||||
}
|
||||
@@ -264,25 +267,23 @@ int asst::DepotImageAnalyzer::match_quantity(const Rect& roi)
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(m_image_draw_resized, utils::make_rect<cv::Rect>(result.rect), cv::Scalar(0, 0, 255));
|
||||
cv::putText(m_image_draw_resized, result.text, cv::Point(result.rect.x, result.rect.y - 5),
|
||||
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2);
|
||||
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2);
|
||||
#endif
|
||||
|
||||
std::string digit_str = result.text;
|
||||
int multiple = 1;
|
||||
if (size_t w_pos = digit_str.find("万");
|
||||
w_pos != std::string::npos) {
|
||||
if (size_t w_pos = digit_str.find("万"); w_pos != std::string::npos) {
|
||||
multiple = 10000;
|
||||
digit_str.erase(w_pos, digit_str.size());
|
||||
}
|
||||
//else if (size_t e_pos = digit_str.find("亿");
|
||||
// e_pos != std::string::npos) {
|
||||
// multiple = 100000000;
|
||||
// digit_str.erase(e_pos, digit_str.size());
|
||||
//}
|
||||
// else if (size_t e_pos = digit_str.find("亿");
|
||||
// e_pos != std::string::npos) {
|
||||
// multiple = 100000000;
|
||||
// digit_str.erase(e_pos, digit_str.size());
|
||||
// }
|
||||
|
||||
if (digit_str.empty() ||
|
||||
!ranges::all_of(digit_str,
|
||||
[](const char& c) -> bool {return std::isdigit(c) || c == '.';})) {
|
||||
!ranges::all_of(digit_str, [](const char& c) -> bool { return std::isdigit(c) || c == '.'; })) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace asst
|
||||
{
|
||||
public:
|
||||
constexpr static size_t NPos = ~0ULL;
|
||||
|
||||
public:
|
||||
using AbstractImageAnalyzer::AbstractImageAnalyzer;
|
||||
virtual ~DepotImageAnalyzer() override = default;
|
||||
@@ -22,10 +23,7 @@ namespace asst
|
||||
|
||||
void set_match_begin_pos(size_t pos) noexcept;
|
||||
size_t get_match_begin_pos() const noexcept;
|
||||
const auto& get_result() const noexcept
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
const auto& get_result() const noexcept { return m_result; }
|
||||
|
||||
private:
|
||||
void resize();
|
||||
@@ -33,7 +31,8 @@ namespace asst
|
||||
bool analyze_all_items();
|
||||
|
||||
bool check_roi_empty(const Rect& roi);
|
||||
size_t match_item(const Rect& roi, /* out */ ItemInfo& item_info, size_t begin_index = 0ULL, bool with_enlarge = true);
|
||||
size_t match_item(const Rect& roi, /* out */ ItemInfo& item_info, size_t begin_index = 0ULL,
|
||||
bool with_enlarge = true);
|
||||
int match_quantity(const Rect& roi);
|
||||
Rect resize_rect_to_raw_size(const Rect& rect);
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#include <meojson/json.hpp>
|
||||
|
||||
#include "Logger.hpp"
|
||||
#include "Controller.h"
|
||||
#include "TaskData.h"
|
||||
#include "DepotImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
#include "Logger.hpp"
|
||||
#include "ProcessTask.h"
|
||||
#include "Resource.h"
|
||||
#include "TaskData.h"
|
||||
|
||||
bool asst::DepotRecognitionTask::_run()
|
||||
{
|
||||
@@ -34,7 +34,7 @@ bool asst::DepotRecognitionTask::swipe_and_analyze()
|
||||
|
||||
// 因为滑动不是完整的一页,有可能上一次识别过的物品,这次仍然在页面中
|
||||
// 所以这个 begin pos 不能设置
|
||||
//analyzer.set_match_begin_pos(pre_pos);
|
||||
// analyzer.set_match_begin_pos(pre_pos);
|
||||
if (!analyzer.analyze()) {
|
||||
break;
|
||||
}
|
||||
@@ -69,12 +69,7 @@ void asst::DepotRecognitionTask::callback_analyze_result()
|
||||
|
||||
for (const auto& [item_id, item_info] : m_all_items) {
|
||||
arkplanner_data_items.array_emplace(
|
||||
json::object({
|
||||
{ "id", item_id },
|
||||
{ "have", item_info.quantity },
|
||||
{ "name", item_info.item_name }
|
||||
})
|
||||
);
|
||||
json::object({ { "id", item_id }, { "have", item_info.quantity }, { "name", item_info.item_name } }));
|
||||
}
|
||||
arkplanner["data"] = arkplanner_obj.to_string();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "DepotTask.h"
|
||||
|
||||
#include "ProcessTask.h"
|
||||
#include "DepotRecognitionTask.h"
|
||||
#include "ProcessTask.h"
|
||||
|
||||
asst::DepotTask::DepotTask(AsstCallback callback, void* callback_arg)
|
||||
: PackageTask(std::move(callback), callback_arg, TaskType)
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace asst
|
||||
virtual ~DepotTask() override = default;
|
||||
|
||||
static constexpr const char* TaskType = "Depot";
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#include "DrGrandetTaskPlugin.h"
|
||||
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "Controller.h"
|
||||
#include "TaskData.h"
|
||||
#include "Logger.hpp"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "TaskData.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
bool asst::DrGrandetTaskPlugin::verify(AsstMsg msg, const json::value& details) const
|
||||
{
|
||||
if (msg != AsstMsg::SubTaskStart
|
||||
|| details.get("subtask", std::string()) != "ProcessTask") {
|
||||
if (msg != AsstMsg::SubTaskStart || details.get("subtask", std::string()) != "ProcessTask") {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
|
||||
bool asst::DronesForShamareTaskPlugin::verify(AsstMsg msg, const json::value& details) const
|
||||
{
|
||||
if (msg != AsstMsg::SubTaskExtraInfo
|
||||
|| details.get("subtask", std::string()) != "InfrastTradeTask") {
|
||||
if (msg != AsstMsg::SubTaskExtraInfo || details.get("subtask", std::string()) != "InfrastTradeTask") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (details.at("what").as_string() == "ProductOfFacility"
|
||||
&& details.at("details").at("product").as_string() == "Money"
|
||||
&& m_cast_ptr->get_uses_of_drone() == "Money") {
|
||||
if (details.at("what").as_string() == "ProductOfFacility" &&
|
||||
details.at("details").at("product").as_string() == "Money" && m_cast_ptr->get_uses_of_drone() == "Money") {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -2,22 +2,21 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "DrGrandetTaskPlugin.h"
|
||||
#include "GameCrashRestartTaskPlugin.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "StageDropsTaskPlugin.h"
|
||||
#include "GameCrashRestartTaskPlugin.h"
|
||||
#include "StageNavigationTask.h"
|
||||
#include "DrGrandetTaskPlugin.h"
|
||||
|
||||
asst::FightTask::FightTask(AsstCallback callback, void* callback_arg)
|
||||
: PackageTask(std::move(callback), callback_arg, TaskType),
|
||||
m_start_up_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType)),
|
||||
m_last_battle_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType)),
|
||||
m_stage_navigation_task_ptr(std::make_shared<StageNavigationTask>(m_callback, m_callback_arg, TaskType)),
|
||||
m_fight_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType))
|
||||
m_start_up_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType)),
|
||||
m_last_battle_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType)),
|
||||
m_stage_navigation_task_ptr(std::make_shared<StageNavigationTask>(m_callback, m_callback_arg, TaskType)),
|
||||
m_fight_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType))
|
||||
{
|
||||
// 进入选关界面(主界面的“终端”点进去)
|
||||
m_start_up_task_ptr->
|
||||
set_times_limit("GoLastBattle", 0)
|
||||
m_start_up_task_ptr->set_times_limit("GoLastBattle", 0)
|
||||
.set_times_limit("StartButton1", 0)
|
||||
.set_times_limit("StartButton2", 0)
|
||||
.set_times_limit("MedicineConfirm", 0)
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace asst
|
||||
virtual bool set_params(const json::value& params) override;
|
||||
|
||||
static constexpr const char* TaskType = "Fight";
|
||||
protected:
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ProcessTask> m_start_up_task_ptr = nullptr;
|
||||
std::shared_ptr<ProcessTask> m_last_battle_task_ptr = nullptr;
|
||||
std::shared_ptr<StageNavigationTask> m_stage_navigation_task_ptr = nullptr;
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
|
||||
bool asst::GameCrashRestartTaskPlugin::verify(AsstMsg msg, const json::value& details) const
|
||||
{
|
||||
if (msg != AsstMsg::SubTaskStart
|
||||
|| details.get("subtask", std::string()) != "ProcessTask") {
|
||||
if (msg != AsstMsg::SubTaskStart || details.get("subtask", std::string()) != "ProcessTask") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (details.at("details").at("task").as_string() == "RestartGameAndContinueFighting"
|
||||
&& m_status->get_number("LastStartButton2")) {
|
||||
if (details.at("details").at("task").as_string() == "RestartGameAndContinueFighting" &&
|
||||
m_status->get_number("LastStartButton2")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "GeneralConfiger.h"
|
||||
|
||||
#include <meojson/json.hpp>
|
||||
#include "Logger.hpp"
|
||||
#include <meojson/json.hpp>
|
||||
|
||||
bool asst::GeneralConfiger::parse(const json::value& json)
|
||||
{
|
||||
@@ -14,12 +14,13 @@ bool asst::GeneralConfiger::parse(const json::value& json)
|
||||
m_options.task_delay = options_json.at("taskDelay").as_integer();
|
||||
m_options.control_delay_lower = options_json.at("controlDelayRange")[0].as_integer();
|
||||
m_options.control_delay_upper = options_json.at("controlDelayRange")[1].as_integer();
|
||||
//m_options.print_window = options_json.at("printWindow").as_boolean();
|
||||
// m_options.print_window = options_json.at("printWindow").as_boolean();
|
||||
m_options.adb_extra_swipe_dist = options_json.get("adbExtraSwipeDist", 100);
|
||||
m_options.adb_extra_swipe_duration = options_json.get("adbExtraSwipeDuration", -1);
|
||||
m_options.penguin_report.cmd_format = options_json.get("penguinReport", "cmdFormat", std::string());
|
||||
m_options.yituliu_report.cmd_format = options_json.get("yituliuReport", "cmdFormat", std::string());
|
||||
m_options.depot_export_template.ark_planner = options_json.get("depotExportTemplate", "arkPlanner", std::string());
|
||||
m_options.depot_export_template.ark_planner =
|
||||
options_json.get("depotExportTemplate", "arkPlanner", std::string());
|
||||
}
|
||||
|
||||
for (const auto& [client_type, intent_name] : json.at("intent").as_object()) {
|
||||
@@ -46,7 +47,7 @@ bool asst::GeneralConfiger::parse(const json::value& json)
|
||||
adb.release = cfg_json.at("release").as_string();
|
||||
adb.start = cfg_json.at("start").as_string();
|
||||
adb.stop = cfg_json.at("stop").as_string();
|
||||
//adb.pullscreen = cfg_json.at("pullscreen").as_string();
|
||||
// adb.pullscreen = cfg_json.at("pullscreen").as_string();
|
||||
|
||||
m_adb_cfg[name] = std::move(adb);
|
||||
}
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
#include "AbstractConfiger.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
|
||||
#include "AsstTypes.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
struct PenguinReportCfg // 企鹅物流数据汇报 的配置
|
||||
struct PenguinReportCfg // 企鹅物流数据汇报 的配置
|
||||
{
|
||||
std::string cmd_format; // 命令格式
|
||||
std::string cmd_format; // 命令格式
|
||||
};
|
||||
|
||||
struct DepotExportTemplate
|
||||
@@ -21,22 +21,28 @@ namespace asst
|
||||
std::string ark_planner;
|
||||
};
|
||||
|
||||
struct yituliuReportCfg // 一图流大数据汇报 的配置
|
||||
struct yituliuReportCfg // 一图流大数据汇报 的配置
|
||||
{
|
||||
std::string cmd_format; // 命令格式
|
||||
std::string cmd_format; // 命令格式
|
||||
};
|
||||
|
||||
struct Options
|
||||
{
|
||||
int task_delay = 0; // 任务间延时:越快操作越快,但会增加CPU消耗
|
||||
int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时
|
||||
int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时
|
||||
//bool print_window = false; // 截图功能:开启后每次结算界面会截图到screenshot目录下
|
||||
int adb_extra_swipe_dist = 0; // 额外的滑动距离:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来
|
||||
int adb_extra_swipe_duration = -1; // 额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能
|
||||
PenguinReportCfg penguin_report; // 企鹅物流汇报:每次到结算界面,汇报掉落数据至企鹅物流 https://penguin-stats.cn/
|
||||
DepotExportTemplate depot_export_template; // 仓库识别结果导出模板
|
||||
yituliuReportCfg yituliu_report; // 一图流大数据汇报:目前只有公招功能,https://yituliu.site/maarecruitdata
|
||||
int task_delay = 0; // 任务间延时:越快操作越快,但会增加CPU消耗
|
||||
int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时
|
||||
int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时
|
||||
// bool print_window = false;// 截图功能:开启后每次结算界面会截图到screenshot目录下
|
||||
int adb_extra_swipe_dist = 0; // 额外的滑动距离:
|
||||
// adb有bug,同样的参数,偶尔会划得非常远。
|
||||
// 额外做一个短程滑动,把之前的停下来。
|
||||
int adb_extra_swipe_duration = -1; // 额外的滑动持续时间:
|
||||
// adb有bug,同样的参数,偶尔会划得非常远。
|
||||
// 额外做一个短程滑动,把之前的停下来。
|
||||
// 若小于0,则关闭额外滑动功能。
|
||||
PenguinReportCfg penguin_report; // 企鹅物流汇报:
|
||||
// 每次到结算界面,汇报掉落数据至企鹅物流 https://penguin-stats.cn/
|
||||
DepotExportTemplate depot_export_template; // 仓库识别结果导出模板
|
||||
yituliuReportCfg yituliu_report; // 一图流大数据汇报:目前只有公招功能,https://yituliu.site/maarecruitdata
|
||||
};
|
||||
|
||||
struct AdbCfg
|
||||
@@ -68,22 +74,12 @@ namespace asst
|
||||
public:
|
||||
virtual ~GeneralConfiger() override = default;
|
||||
|
||||
const std::string& get_version() const noexcept
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
const Options& get_options() const noexcept
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
Options& get_options()
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
const std::string& get_version() const noexcept { return m_version; }
|
||||
const Options& get_options() const noexcept { return m_options; }
|
||||
Options& get_options() { return m_options; }
|
||||
std::optional<AdbCfg> get_adb_cfg(const std::string& name) const
|
||||
{
|
||||
if (auto iter = m_adb_cfg.find(name);
|
||||
iter != m_adb_cfg.cend()) {
|
||||
if (auto iter = m_adb_cfg.find(name); iter != m_adb_cfg.cend()) {
|
||||
return iter->second;
|
||||
}
|
||||
else {
|
||||
@@ -93,17 +89,13 @@ namespace asst
|
||||
|
||||
std::optional<std::string> get_intent_name(const std::string& client_type) const
|
||||
{
|
||||
if (auto iter = m_intent_name.find(client_type);
|
||||
iter != m_intent_name.cend()) {
|
||||
if (auto iter = m_intent_name.find(client_type); iter != m_intent_name.cend()) {
|
||||
return iter->second;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void set_options(Options opt) noexcept
|
||||
{
|
||||
m_options = std::move(opt);
|
||||
}
|
||||
void set_options(Options opt) noexcept { m_options = std::move(opt); }
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
@@ -113,4 +105,4 @@ namespace asst
|
||||
std::unordered_map<std::string, AdbCfg> m_adb_cfg;
|
||||
std::unordered_map<std::string, std::string> m_intent_name;
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -34,13 +34,13 @@ bool asst::HashImageAnalyzer::analyze()
|
||||
to_hash = bound_bin(to_hash);
|
||||
}
|
||||
std::string hash_result = s_hash(to_hash);
|
||||
//Log.debug(hash_result);
|
||||
// Log.debug(hash_result);
|
||||
|
||||
int min_dist = INT_MAX;
|
||||
std::string cur_min_dist_name;
|
||||
for (auto&& [name, templ] : m_hash_templates) {
|
||||
int hm = hamming(hash_result, templ);
|
||||
//Log.debug(name, "dist:", hm);
|
||||
// Log.debug(name, "dist:", hm);
|
||||
if (hm < min_dist) {
|
||||
cur_min_dist_name = name;
|
||||
min_dist = hm;
|
||||
@@ -103,8 +103,7 @@ std::string asst::HashImageAnalyzer::s_hash(const cv::Mat& img)
|
||||
int tmp_dec = 0;
|
||||
for (int ro = 0; ro < 256; ro++) {
|
||||
tmp_dec = tmp_dec << 1;
|
||||
if (*pix > 127)
|
||||
tmp_dec++;
|
||||
if (*pix > 127) tmp_dec++;
|
||||
if (ro % 4 == 3) {
|
||||
hash_value << std::hex << tmp_dec;
|
||||
tmp_dec = 0;
|
||||
@@ -162,8 +161,8 @@ int asst::HashImageAnalyzer::hamming(std::string hash1, std::string hash2)
|
||||
hash2.insert(hash2.begin(), HammingFlags - hash2.size(), '0');
|
||||
int dist = 0;
|
||||
for (int i = 0; i < HammingFlags; i = i + 16) {
|
||||
unsigned long long x = strtoull(hash1.substr(i, 16).c_str(), nullptr, 16)
|
||||
^ strtoull(hash2.substr(i, 16).c_str(), nullptr, 16);
|
||||
unsigned long long x =
|
||||
strtoull(hash1.substr(i, 16).c_str(), nullptr, 16) ^ strtoull(hash2.substr(i, 16).c_str(), nullptr, 16);
|
||||
while (x) {
|
||||
++dist;
|
||||
x = x & (x - 1);
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace asst
|
||||
static cv::Mat bound_bin(const cv::Mat& bin);
|
||||
|
||||
protected:
|
||||
|
||||
std::pair<int, int> m_mask_range;
|
||||
std::unordered_map<std::string, std::string> m_hash_templates;
|
||||
bool m_need_split = false;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#include "Logger.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "Resource.h"
|
||||
|
||||
asst::InfrastAbstractTask::InfrastAbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain)
|
||||
: AbstractTask(std::move(callback), callback_arg, std::move(task_chain))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "AbstractTask.h"
|
||||
#include "AsstTypes.h"
|
||||
#include "AsstInfrastDef.h"
|
||||
#include "AsstTypes.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
@@ -21,6 +21,7 @@ namespace asst
|
||||
|
||||
constexpr static int OperSelectRetryTimes = 3;
|
||||
constexpr static int TaskRetryTimes = 3;
|
||||
|
||||
protected:
|
||||
virtual bool on_run_fails() override;
|
||||
|
||||
@@ -28,17 +29,17 @@ namespace asst
|
||||
bool enter_oper_list_page(); // 从刚点进设施的界面,到干员列表页
|
||||
|
||||
void swipe_to_the_left_of_operlist(int loop_times = 1); // 滑动到干员列表的最左侧
|
||||
void swipe_to_the_left_of_main_ui(); // 滑动基建的主界面到最左侧
|
||||
void swipe_to_the_right_of_main_ui(); // 滑动基建的主界面到最右侧
|
||||
void swipe_to_the_left_of_main_ui(); // 滑动基建的主界面到最左侧
|
||||
void swipe_to_the_right_of_main_ui(); // 滑动基建的主界面到最右侧
|
||||
void swipe_of_operlist(bool reverse = false);
|
||||
void async_swipe_of_operlist(bool reverse = false);
|
||||
void await_swipe();
|
||||
|
||||
virtual bool click_bottom_left_tab(); // 点击进入设施后,左下角的tab(我也不知道这玩意该叫啥)
|
||||
virtual bool click_clear_button(); // 点击干员选择页面的“清空选择”按钮
|
||||
virtual bool click_sort_by_trust_button();// 点击干员选择页面的“按信赖值排序”按钮
|
||||
virtual bool click_filter_menu_not_stationed_button();// 点击干员选择页面的筛选菜单按钮的“未进驻”按钮
|
||||
virtual bool click_confirm_button(); // 点击干员选择页面的“确认”按钮
|
||||
virtual bool click_clear_button(); // 点击干员选择页面的“清空选择”按钮
|
||||
virtual bool click_sort_by_trust_button(); // 点击干员选择页面的“按信赖值排序”按钮
|
||||
virtual bool click_filter_menu_not_stationed_button(); // 点击干员选择页面的筛选菜单按钮的“未进驻”按钮
|
||||
virtual bool click_confirm_button(); // 点击干员选择页面的“确认”按钮
|
||||
|
||||
int m_last_swipe_id = 0;
|
||||
infrast::WorkMode m_work_mode = infrast::WorkMode::Aggressive;
|
||||
|
||||
@@ -11,10 +11,7 @@ namespace asst
|
||||
|
||||
virtual bool analyze() override;
|
||||
|
||||
const std::vector<std::pair<Rect, std::string>>& get_result() const noexcept
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
const std::vector<std::pair<Rect, std::string>>& get_result() const noexcept { return m_result; }
|
||||
|
||||
protected:
|
||||
bool clue_detect();
|
||||
|
||||
@@ -18,10 +18,7 @@ namespace asst
|
||||
m_to_be_analyzed = std::move(to_be_analyzed);
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, Rect>& get_vacancy() const noexcept
|
||||
{
|
||||
return m_clue_vacancy;
|
||||
}
|
||||
const std::unordered_map<std::string, Rect>& get_vacancy() const noexcept { return m_clue_vacancy; }
|
||||
|
||||
private:
|
||||
// 该分析器不支持外部设置ROI
|
||||
|
||||
@@ -38,8 +38,7 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
const json::value& efficient = *opt;
|
||||
const static std::string reg_suffix = "_reg";
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
if (std::string all_reg_key = "all" + reg_suffix; efficient.contains(all_reg_key)) {
|
||||
std::string all_reg_value = efficient.at(all_reg_key).as_string();
|
||||
for (const std::string& pd : products) {
|
||||
skill.efficient_regex.emplace(pd, all_reg_value);
|
||||
@@ -54,8 +53,7 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix;
|
||||
efficient.contains(pd_reg_key)) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix; efficient.contains(pd_reg_key)) {
|
||||
skill.efficient_regex.emplace(pd, efficient.at(pd_reg_key).as_string());
|
||||
skill.efficient.emplace(pd, 0);
|
||||
}
|
||||
@@ -102,8 +100,7 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
const static std::string reg_suffix = "_reg";
|
||||
const json::value& efficient = necessary_json.at("efficient");
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
if (std::string all_reg_key = "all" + reg_suffix; efficient.contains(all_reg_key)) {
|
||||
std::string all_reg_value = efficient.at(all_reg_key).as_string();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient_regex.emplace(pd, all_reg_value);
|
||||
@@ -118,8 +115,7 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix;
|
||||
efficient.contains(pd_reg_key)) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix; efficient.contains(pd_reg_key)) {
|
||||
comb.efficient_regex.emplace(pd, efficient.at(pd_reg_key).as_string());
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
@@ -156,8 +152,7 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
const static std::string reg_suffix = "_reg";
|
||||
const json::value& efficient = opt_json.at("efficient");
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
if (std::string all_reg_key = "all" + reg_suffix; efficient.contains(all_reg_key)) {
|
||||
std::string all_reg_value = efficient.at(all_reg_key).as_string();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient_regex.emplace(pd, all_reg_value);
|
||||
@@ -172,8 +167,7 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix;
|
||||
efficient.contains(pd_reg_key)) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix; efficient.contains(pd_reg_key)) {
|
||||
comb.efficient_regex.emplace(pd, efficient.at(pd_reg_key).as_string());
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
|
||||
@@ -13,11 +13,9 @@ namespace asst
|
||||
public:
|
||||
virtual ~InfrastConfiger() override = default;
|
||||
|
||||
auto get_templ_required() const noexcept -> const std::unordered_set<std::string>&
|
||||
{
|
||||
return m_templ_required;
|
||||
}
|
||||
auto get_skills(const std::string& facility_name) const -> const std::unordered_map<std::string, infrast::Skill>&
|
||||
auto get_templ_required() const noexcept -> const std::unordered_set<std::string>& { return m_templ_required; }
|
||||
auto get_skills(const std::string& facility_name) const
|
||||
-> const std::unordered_map<std::string, infrast::Skill>&
|
||||
{
|
||||
return m_skills.at(facility_name);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace asst
|
||||
virtual ~InfrastControlTask() override = default;
|
||||
|
||||
virtual size_t max_num_of_opers() const noexcept override { return 5ULL; }
|
||||
|
||||
private:
|
||||
virtual bool _run() override;
|
||||
};
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#include "Logger.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "OcrWithPreprocessImageAnalyzer.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "Resource.h"
|
||||
#include "OcrWithPreprocessImageAnalyzer.h"
|
||||
#include <regex>
|
||||
|
||||
asst::InfrastDormTask& asst::InfrastDormTask::set_notstationed_enabled(bool notstationed_enabled) noexcept
|
||||
@@ -50,7 +50,7 @@ bool asst::InfrastDormTask::_run()
|
||||
click_confirm_button();
|
||||
click_return_button();
|
||||
|
||||
if (m_finished_stage == 3) {//不蹭信赖或所有干员满信赖
|
||||
if (m_finished_stage == 3) { //不蹭信赖或所有干员满信赖
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -90,17 +90,18 @@ bool asst::InfrastDormTask::opers_choose()
|
||||
switch (oper.smiley.type) {
|
||||
case infrast::SmileyType::Rest:
|
||||
// 如果所有心情不满的干员已经放入宿舍,就把信赖不满的干员放入宿舍
|
||||
if (m_trust_enabled && m_finished_stage > 0 && oper.selected == false && oper.doing != infrast::Doing::Working && oper.doing != infrast::Doing::Resting) {
|
||||
if (m_trust_enabled && m_finished_stage > 0 && oper.selected == false &&
|
||||
oper.doing != infrast::Doing::Working && oper.doing != infrast::Doing::Resting) {
|
||||
|
||||
//获得干员信赖值
|
||||
OcrWithPreprocessImageAnalyzer trust_analyzer(oper.name_img);
|
||||
if (!trust_analyzer.analyze()) {
|
||||
Log.trace("ERROR:!trust_analyzer.analyze():");
|
||||
//return false;
|
||||
// return false;
|
||||
}
|
||||
|
||||
std::string opertrust = trust_analyzer.get_result().front().text;
|
||||
std::regex rule("[^0-9]");//只保留数字
|
||||
std::regex rule("[^0-9]"); //只保留数字
|
||||
opertrust = std::regex_replace(opertrust, rule, "");
|
||||
|
||||
Log.trace("opertrust:", opertrust);
|
||||
@@ -112,26 +113,25 @@ bool asst::InfrastDormTask::opers_choose()
|
||||
else if (opertrust != "" && atoi(opertrust.c_str()) >= 200) {
|
||||
num_of_fulltrust++;
|
||||
}
|
||||
if (num_of_fulltrust >= 6) {//所有干员都满信赖了
|
||||
if (num_of_fulltrust >= 6) { //所有干员都满信赖了
|
||||
m_finished_stage = 3;
|
||||
Log.trace("num_of_fulltrust:", num_of_fulltrust, ", just return");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//获得干员所在设施
|
||||
OcrWithPreprocessImageAnalyzer facility_analyzer(oper.facility_img);
|
||||
if (!facility_analyzer.analyze()) {
|
||||
Log.trace("ERROR:!facility_analyzer.analyze():");
|
||||
//return false;
|
||||
// return false;
|
||||
}
|
||||
|
||||
std::string facilityname = facility_analyzer.get_result().front().text;
|
||||
std::regex rule2("[^BF0-9]");//只保留B、F和数字
|
||||
std::regex rule2("[^BF0-9]"); //只保留B、F和数字
|
||||
facilityname = std::regex_replace(facilityname, rule2, "");
|
||||
|
||||
Log.trace("facilityname:<" + facilityname + ">");
|
||||
bool if_oper_not_stationed = facilityname.length() < 4;//只有形如1F01或B101才是设施标签
|
||||
bool if_oper_not_stationed = facilityname.length() < 4; //只有形如1F01或B101才是设施标签
|
||||
|
||||
//判断要不要把人放进宿舍if_opertrust_not_full && if_oper_not_stationed
|
||||
if (if_opertrust_not_full && if_oper_not_stationed) {
|
||||
@@ -146,7 +146,6 @@ bool asst::InfrastDormTask::opers_choose()
|
||||
else {
|
||||
Log.trace("not put oper in");
|
||||
}
|
||||
|
||||
}
|
||||
// 如果当前页面休息完成的人数超过5个,说明已经已经把所有心情不满的滑过一遍、没有更多的了
|
||||
else if (++num_of_resting > max_num_of_opers()) {
|
||||
@@ -160,7 +159,7 @@ bool asst::InfrastDormTask::opers_choose()
|
||||
}
|
||||
Log.trace("click_sort_by_trust_button");
|
||||
click_sort_by_trust_button();
|
||||
m_finished_stage = 1;// 选中未进驻标签并按信赖值排序
|
||||
m_finished_stage = 1; // 选中未进驻标签并按信赖值排序
|
||||
}
|
||||
else {
|
||||
m_finished_stage = 3;
|
||||
@@ -208,10 +207,10 @@ bool asst::InfrastDormTask::opers_choose()
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool asst::InfrastDormTask::click_confirm_button()
|
||||
// bool asst::InfrastDormTask::click_confirm_button()
|
||||
//{
|
||||
// LogTraceFunction;
|
||||
// LogTraceFunction;
|
||||
//
|
||||
// ProcessTask task(*this, { "InfrastDormConfirmButton" });
|
||||
// return task.run();
|
||||
//}
|
||||
// ProcessTask task(*this, { "InfrastDormConfirmButton" });
|
||||
// return task.run();
|
||||
// }
|
||||
|
||||
@@ -16,22 +16,22 @@ namespace asst
|
||||
|
||||
private:
|
||||
virtual bool _run() override;
|
||||
//virtual bool click_confirm_button() override;
|
||||
// virtual bool click_confirm_button() override;
|
||||
|
||||
bool opers_choose();
|
||||
|
||||
bool m_notstationed_enabled = false;//设置是否启用未进驻筛选
|
||||
bool m_trust_enabled = true;//设置是否启用蹭信赖
|
||||
bool m_notstationed_enabled = false; //设置是否启用未进驻筛选
|
||||
bool m_trust_enabled = true; //设置是否启用蹭信赖
|
||||
|
||||
int m_cur_dorm_index = 0;
|
||||
int m_max_num_of_dorm = 4;
|
||||
/*
|
||||
* m_finished_stage
|
||||
* 0:心情恢复阶段
|
||||
* 1:心情恢复完成
|
||||
* 2:蹭信赖阶段
|
||||
* 3:全部任务完成
|
||||
*/
|
||||
* m_finished_stage
|
||||
* 0:心情恢复阶段
|
||||
* 1:心情恢复完成
|
||||
* 2:蹭信赖阶段
|
||||
* 3:全部任务完成
|
||||
*/
|
||||
int m_finished_stage = 0;
|
||||
bool m_if_filter_notstationed_haspressed = false;
|
||||
};
|
||||
|
||||
@@ -9,15 +9,10 @@
|
||||
|
||||
bool asst::InfrastFacilityImageAnalyzer::analyze()
|
||||
{
|
||||
const static std::unordered_map<std::string, std::string>
|
||||
facility_task_name = {
|
||||
{ "Dorm", "InfrastDorm" },
|
||||
{ "Control", "InfrastControl" },
|
||||
{ "Mfg", "InfrastMfg" },
|
||||
{ "Trade", "InfrastTrade" },
|
||||
{ "Power", "InfrastPower" },
|
||||
{ "Office", "InfrastOffice" },
|
||||
{ "Reception", "InfrastReception" }
|
||||
const static std::unordered_map<std::string, std::string> facility_task_name = {
|
||||
{ "Dorm", "InfrastDorm" }, { "Control", "InfrastControl" }, { "Mfg", "InfrastMfg" },
|
||||
{ "Trade", "InfrastTrade" }, { "Power", "InfrastPower" }, { "Office", "InfrastOffice" },
|
||||
{ "Reception", "InfrastReception" }
|
||||
};
|
||||
// 因为基建的缩放是不确定的,有可能是正常大小,也可能是最小化的
|
||||
// 所以对每种情况都进行一下识别,取其中得分最高的
|
||||
@@ -57,12 +52,11 @@ bool asst::InfrastFacilityImageAnalyzer::analyze()
|
||||
}
|
||||
|
||||
const auto& cur_res = mm_analyzer.get_result();
|
||||
auto cur_max_iter = ranges::max_element(cur_res, std::less{}, std::mem_fn(&MatchRect::score));
|
||||
auto cur_max_iter = ranges::max_element(cur_res, std::less {}, std::mem_fn(&MatchRect::score));
|
||||
if (cur_max_iter == cur_res.cend()) {
|
||||
continue;
|
||||
}
|
||||
if (double cur_score = cur_max_iter->score;
|
||||
max_score < cur_score) {
|
||||
if (double cur_score = cur_max_iter->score; max_score < cur_score) {
|
||||
mm_analyzer.sort_result_horizontal();
|
||||
max_score = cur_score;
|
||||
cur_facility_result = cur_res;
|
||||
|
||||
@@ -19,8 +19,7 @@ namespace asst
|
||||
|
||||
size_t get_quantity(const std::string& name) const
|
||||
{
|
||||
if (auto iter = m_result.find(name);
|
||||
iter == m_result.cend()) {
|
||||
if (auto iter = m_result.find(name); iter == m_result.cend()) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
@@ -29,8 +28,7 @@ namespace asst
|
||||
}
|
||||
Rect get_rect(const std::string& name, int index) const
|
||||
{
|
||||
if (auto iter = m_result.find(name);
|
||||
iter == m_result.cend()) {
|
||||
if (auto iter = m_result.find(name); iter == m_result.cend()) {
|
||||
return {};
|
||||
}
|
||||
else {
|
||||
@@ -42,10 +40,7 @@ namespace asst
|
||||
}
|
||||
}
|
||||
}
|
||||
const std::unordered_map<std::string, std::vector<MatchRect>>& get_result() const noexcept
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
const std::unordered_map<std::string, std::vector<MatchRect>>& get_result() const noexcept { return m_result; }
|
||||
|
||||
private:
|
||||
// 该分析器不支持外部设置ROI
|
||||
|
||||
@@ -19,7 +19,7 @@ bool asst::InfrastInfoTask::_run()
|
||||
}
|
||||
for (auto&& [name, res] : analyzer.get_result()) {
|
||||
std::string key = "NumOf" + name;
|
||||
//int size = static_cast<int>(res.size());
|
||||
// int size = static_cast<int>(res.size());
|
||||
m_status->set_number(key, res.size());
|
||||
Log.trace("InfrastInfoTask | ", key, res.size());
|
||||
}
|
||||
|
||||
@@ -24,10 +24,8 @@ bool asst::InfrastOfficeTask::_run()
|
||||
}
|
||||
swipe_to_the_left_of_operlist();
|
||||
|
||||
auto find_iter = ranges::find_if(m_all_available_opers,
|
||||
[&](const infrast::Oper& info) -> bool {
|
||||
return info.selected;
|
||||
});
|
||||
auto find_iter =
|
||||
ranges::find_if(m_all_available_opers, [&](const infrast::Oper& info) -> bool { return info.selected; });
|
||||
|
||||
bool need_shift = true;
|
||||
if (find_iter != m_all_available_opers.end()) {
|
||||
@@ -41,8 +39,8 @@ bool asst::InfrastOfficeTask::_run()
|
||||
need_shift = true;
|
||||
// TODO,这里有个bug,全部干员中的selected,和当前的,不一定是同一个页面
|
||||
// 不过目前没影响,反正滑动到最前面了,selected的一定是在最前面
|
||||
//m_ctrler->click(find_iter->rect);
|
||||
//sleep(300);
|
||||
// m_ctrler->click(find_iter->rect);
|
||||
// sleep(300);
|
||||
break;
|
||||
case infrast::WorkMode::Extreme: // TODO
|
||||
break;
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#include "NoWarningCV.h"
|
||||
|
||||
#include "InfrastSmileyImageAnalyzer.h"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "HashImageAnalyzer.h"
|
||||
#include "InfrastSmileyImageAnalyzer.h"
|
||||
#include "Logger.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
|
||||
bool asst::InfrastOperImageAnalyzer::analyze()
|
||||
@@ -87,7 +87,7 @@ void asst::InfrastOperImageAnalyzer::oper_detect()
|
||||
const Rect name_rect_move = Task.get("InfrastOperNameOcr")->rect_move;
|
||||
const Rect facility_rect_move = Task.get("InfrastOperFacilityOcr")->rect_move;
|
||||
const Rect prg_rect_move = Task.get("InfrastOperMoodProgressBar")->roi;
|
||||
const std::vector<Rect> all_rect_move = { skill_rect_move, name_rect_move,facility_rect_move, prg_rect_move };
|
||||
const std::vector<Rect> all_rect_move = { skill_rect_move, name_rect_move, facility_rect_move, prg_rect_move };
|
||||
|
||||
InfrastSmileyImageAnalyzer smiley_analyzer(m_image);
|
||||
|
||||
@@ -297,7 +297,8 @@ void asst::InfrastOperImageAnalyzer::skill_analyze()
|
||||
else if (possible_skills.size() > 1) {
|
||||
// 匹配得分最高的id作为基准,排除有识别错误,其他的技能混进来了的情况
|
||||
// 即排除容器中,除了有同一个技能的不同等级,还有别的技能的情况
|
||||
auto max_iter = ranges::max_element(possible_skills, std::less{}, [](const auto& pair) { return pair.second.score; });
|
||||
auto max_iter = ranges::max_element(possible_skills, std::less {},
|
||||
[](const auto& pair) { return pair.second.score; });
|
||||
double base_score = max_iter->second.score;
|
||||
std::string base_id = max_iter->first.id;
|
||||
size_t level_pos = 0;
|
||||
@@ -315,8 +316,7 @@ void asst::InfrastOperImageAnalyzer::skill_analyze()
|
||||
if (base_score - skill_mr.score > 0.05) {
|
||||
continue;
|
||||
}
|
||||
if (size_t find_pos = skill.id.find(base_id);
|
||||
find_pos != std::string::npos) {
|
||||
if (size_t find_pos = skill.id.find(base_id); find_pos != std::string::npos) {
|
||||
std::string cur_skill_level = skill.id.substr(base_id.size());
|
||||
if (max_level.empty() || cur_skill_level > max_level) {
|
||||
max_level = cur_skill_level;
|
||||
@@ -372,7 +372,7 @@ void asst::InfrastOperImageAnalyzer::selected_analyze()
|
||||
}
|
||||
Log.trace("selected_analyze |", count);
|
||||
oper.selected = count >= selected_task_ptr->templ_threshold;
|
||||
oper.rect = selected_rect; // 先凑合用(
|
||||
oper.rect = selected_rect; // 先凑合用(
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +395,8 @@ void asst::InfrastOperImageAnalyzer::doing_analyze()
|
||||
if (working_analyzer.analyze()) {
|
||||
oper.doing = infrast::Doing::Working;
|
||||
#ifdef ASST_DEBUG
|
||||
cv::putText(m_image_draw, "Working", cv::Point(working_rect.x, working_rect.y), 1, 1, cv::Scalar(0, 0, 255), 2);
|
||||
cv::putText(m_image_draw, "Working", cv::Point(working_rect.x, working_rect.y), 1, 1, cv::Scalar(0, 0, 255),
|
||||
2);
|
||||
#endif
|
||||
}
|
||||
// TODO: infrast::Doing::Resting的识别
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace asst
|
||||
Smiley = 1,
|
||||
Mood = 2,
|
||||
FaceHash = 4,
|
||||
//NameHash = 8,
|
||||
// NameHash = 8,
|
||||
Selected = 16,
|
||||
Doing = 32,
|
||||
Skill = 64,
|
||||
@@ -30,22 +30,10 @@ namespace asst
|
||||
void sort_by_loc();
|
||||
void sort_by_mood();
|
||||
|
||||
auto get_result() const noexcept -> const std::vector<infrast::Oper>&
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
int get_num_of_opers_with_skills() const noexcept
|
||||
{
|
||||
return m_num_of_opers_with_skills;
|
||||
}
|
||||
void set_facility(std::string facility) noexcept
|
||||
{
|
||||
m_facility = std::move(facility);
|
||||
}
|
||||
void set_to_be_calced(int to_be_calced) noexcept
|
||||
{
|
||||
m_to_be_calced = to_be_calced;
|
||||
}
|
||||
auto get_result() const noexcept -> const std::vector<infrast::Oper>& { return m_result; }
|
||||
int get_num_of_opers_with_skills() const noexcept { return m_num_of_opers_with_skills; }
|
||||
void set_facility(std::string facility) noexcept { m_facility = std::move(facility); }
|
||||
void set_to_be_calced(int to_be_calced) noexcept { m_to_be_calced = to_be_calced; }
|
||||
|
||||
constexpr static int MaxNumOfSkills = 2; // 单个干员最多有几个基建技能
|
||||
|
||||
@@ -65,4 +53,4 @@ namespace asst
|
||||
int m_to_be_calced = All;
|
||||
int m_num_of_opers_with_skills = 0;
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -49,8 +49,8 @@ bool asst::InfrastPowerTask::_run()
|
||||
need_shift = true;
|
||||
// TODO,这里有个bug,全部干员中的selected,和当前的,不一定是同一个页面
|
||||
// 不过目前没影响,反正滑动到最前面了,selected的一定是在最前面
|
||||
//m_ctrler->click(find_iter->rect);
|
||||
//sleep(300);
|
||||
// m_ctrler->click(find_iter->rect);
|
||||
// sleep(300);
|
||||
break;
|
||||
case infrast::WorkMode::Extreme: // TODO
|
||||
break;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
#include "InfrastProductionTask.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "AsstRanges.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#include <calculator/calculator.hpp>
|
||||
|
||||
#include "Controller.h"
|
||||
#include "InfrastOperImageAnalyzer.h"
|
||||
#include "HashImageAnalyzer.h"
|
||||
#include "InfrastOperImageAnalyzer.h"
|
||||
#include "Logger.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "MultiMatchImageAnalyzer.h"
|
||||
#include "OcrWithPreprocessImageAnalyzer.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "Resource.h"
|
||||
#include "RuntimeStatus.h"
|
||||
#include "ProcessTask.h"
|
||||
|
||||
asst::InfrastProductionTask& asst::InfrastProductionTask::set_uses_of_drone(std::string uses_of_drones) noexcept
|
||||
{
|
||||
@@ -187,8 +187,8 @@ size_t asst::InfrastProductionTask::opers_detect()
|
||||
const auto& cur_all_opers = oper_analyzer.get_result();
|
||||
max_num_of_opers_per_page = (std::max)(max_num_of_opers_per_page, cur_all_opers.size());
|
||||
|
||||
const int face_hash_thres = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("InfrastOperFaceHash"))->dist_threshold;
|
||||
const int face_hash_thres =
|
||||
std::dynamic_pointer_cast<HashTaskInfo>(Task.get("InfrastOperFaceHash"))->dist_threshold;
|
||||
const size_t pre_size = m_all_available_opers.size();
|
||||
for (const auto& cur_oper : cur_all_opers) {
|
||||
if (cur_oper.skills.empty()) {
|
||||
@@ -207,16 +207,15 @@ size_t asst::InfrastProductionTask::opers_detect()
|
||||
//--cur_available_num;
|
||||
continue;
|
||||
}
|
||||
auto find_iter = ranges::find_if(m_all_available_opers,
|
||||
[&](const infrast::Oper& oper) -> bool {
|
||||
if (oper.skills != cur_oper.skills) {
|
||||
return false;
|
||||
}
|
||||
// 有可能是同一个干员,比一下hash
|
||||
int dist = HashImageAnalyzer::hamming(cur_oper.face_hash, oper.face_hash);
|
||||
Log.debug("opers_detect hash dist |", dist);
|
||||
return dist < face_hash_thres;
|
||||
});
|
||||
auto find_iter = ranges::find_if(m_all_available_opers, [&](const infrast::Oper& oper) -> bool {
|
||||
if (oper.skills != cur_oper.skills) {
|
||||
return false;
|
||||
}
|
||||
// 有可能是同一个干员,比一下hash
|
||||
int dist = HashImageAnalyzer::hamming(cur_oper.face_hash, oper.face_hash);
|
||||
Log.debug("opers_detect hash dist |", dist);
|
||||
return dist < face_hash_thres;
|
||||
});
|
||||
// 如果两个的hash距离过小,则认为是同一个干员,不进行插入
|
||||
if (find_iter != m_all_available_opers.cend()) {
|
||||
continue;
|
||||
@@ -244,10 +243,9 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
std::vector<infrast::SkillsComb> optimal_combs;
|
||||
optimal_combs.reserve(cur_max_num_of_opers);
|
||||
double max_efficient = 0;
|
||||
ranges::sort(all_available_combs,
|
||||
[&](const infrast::SkillsComb& lhs, const infrast::SkillsComb& rhs) -> bool {
|
||||
return lhs.efficient.at(m_product) > rhs.efficient.at(m_product);
|
||||
});
|
||||
ranges::sort(all_available_combs, [&](const infrast::SkillsComb& lhs, const infrast::SkillsComb& rhs) -> bool {
|
||||
return lhs.efficient.at(m_product) > rhs.efficient.at(m_product);
|
||||
});
|
||||
|
||||
for (const auto& comb : all_available_combs) {
|
||||
std::string skill_str;
|
||||
@@ -330,16 +328,13 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
// TODO necessary暂时没做hash校验。因为没有需要比hash的necessary干员(
|
||||
for (const infrast::SkillsComb& nec_skills : group.necessary) {
|
||||
auto find_iter = ranges::find_if(cur_available_opers,
|
||||
[&](const infrast::SkillsComb& arg) -> bool {
|
||||
return arg == nec_skills;
|
||||
});
|
||||
[&](const infrast::SkillsComb& arg) -> bool { return arg == nec_skills; });
|
||||
if (find_iter == cur_available_opers.cend()) {
|
||||
group_unavailable = true;
|
||||
break;
|
||||
}
|
||||
cur_combs.emplace_back(nec_skills);
|
||||
if (auto iter = nec_skills.efficient_regex.find(m_product);
|
||||
iter != nec_skills.efficient_regex.cend()) {
|
||||
if (auto iter = nec_skills.efficient_regex.find(m_product); iter != nec_skills.efficient_regex.cend()) {
|
||||
cur_efficient += efficient_regex_calc(nec_skills.skills).efficient.at(m_product);
|
||||
}
|
||||
else {
|
||||
@@ -353,27 +348,21 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
// 排个序,因为产物不同,效率可能会发生变化,所以配置文件里默认的顺序不一定准确
|
||||
auto optional = group.optional;
|
||||
for (auto&& opt : optional) {
|
||||
if (auto iter = opt.efficient_regex.find(m_product);
|
||||
iter != opt.efficient_regex.cend()) {
|
||||
if (auto iter = opt.efficient_regex.find(m_product); iter != opt.efficient_regex.cend()) {
|
||||
opt = efficient_regex_calc(opt.skills);
|
||||
}
|
||||
}
|
||||
|
||||
ranges::sort(optional,
|
||||
[&](const infrast::SkillsComb& lhs,
|
||||
const infrast::SkillsComb& rhs) -> bool {
|
||||
return lhs.efficient.at(m_product) > rhs.efficient.at(m_product);
|
||||
});
|
||||
ranges::sort(optional, [&](const infrast::SkillsComb& lhs, const infrast::SkillsComb& rhs) -> bool {
|
||||
return lhs.efficient.at(m_product) > rhs.efficient.at(m_product);
|
||||
});
|
||||
|
||||
// 可能有多个干员有同样的技能,所以这里需要循环找同一个技能,直到找不到为止
|
||||
for (const infrast::SkillsComb& opt : optional) {
|
||||
auto find_iter = cur_available_opers.cbegin();
|
||||
while (cur_combs.size() != cur_max_num_of_opers) {
|
||||
find_iter = std::find_if(
|
||||
find_iter, cur_available_opers.cend(),
|
||||
[&](const infrast::SkillsComb& arg) -> bool {
|
||||
return arg == opt;
|
||||
});
|
||||
find_iter = std::find_if(find_iter, cur_available_opers.cend(),
|
||||
[&](const infrast::SkillsComb& arg) -> bool { return arg == opt; });
|
||||
if (find_iter != cur_available_opers.cend()) {
|
||||
bool hash_matched = false;
|
||||
if (opt.name_filter.empty()) {
|
||||
@@ -381,8 +370,7 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
}
|
||||
else {
|
||||
OcrWithPreprocessImageAnalyzer name_analyzer(find_iter->name_img);
|
||||
name_analyzer.set_replace(
|
||||
Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
name_analyzer.set_replace(Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
Log.trace("Analyze name filter");
|
||||
if (!name_analyzer.analyze()) {
|
||||
continue;
|
||||
@@ -457,8 +445,8 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
auto& facility_info = Resrc.infrast().get_facility_info(facility_name());
|
||||
int cur_max_num_of_opers = facility_info.max_num_of_opers - m_cur_num_of_locked_opers;
|
||||
|
||||
const int face_hash_thres = std::dynamic_pointer_cast<HashTaskInfo>(
|
||||
Task.get("InfrastOperFaceHash"))->dist_threshold;
|
||||
const int face_hash_thres =
|
||||
std::dynamic_pointer_cast<HashTaskInfo>(Task.get("InfrastOperFaceHash"))->dist_threshold;
|
||||
|
||||
int count = 0;
|
||||
|
||||
@@ -493,83 +481,78 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
auto cur_all_opers = oper_analyzer.get_result();
|
||||
Log.trace("before mood filter, opers size:", cur_all_opers.size());
|
||||
// 小于心情阈值的干员则不可用
|
||||
auto remove_iter = ranges::remove_if(cur_all_opers,
|
||||
[&](const infrast::Oper& rhs) -> bool {
|
||||
return rhs.mood_ratio < m_mood_threshold;
|
||||
}).begin();
|
||||
cur_all_opers.erase(remove_iter, cur_all_opers.end());
|
||||
Log.trace("after mood filter, opers size:", cur_all_opers.size());
|
||||
for (auto opt_iter = m_optimal_combs.begin(); opt_iter != m_optimal_combs.end();) {
|
||||
Log.trace("to find", opt_iter->skills.begin()->names.front());
|
||||
auto find_iter = ranges::find_if(cur_all_opers,
|
||||
[&](const infrast::Oper& lhs) -> bool {
|
||||
if (lhs.skills != opt_iter->skills) {
|
||||
return false;
|
||||
}
|
||||
if (opt_iter->name_filter.empty()) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
OcrWithPreprocessImageAnalyzer name_analyzer(lhs.name_img);
|
||||
name_analyzer.set_replace(
|
||||
Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
Log.trace("Analyze name filter");
|
||||
if (!name_analyzer.analyze()) {
|
||||
return false;
|
||||
}
|
||||
std::string name = name_analyzer.get_result().front().text;
|
||||
return ranges::find(std::as_const(opt_iter->name_filter), name) != opt_iter->name_filter.cend();
|
||||
}
|
||||
});
|
||||
|
||||
if (find_iter == cur_all_opers.cend()) {
|
||||
++opt_iter;
|
||||
Log.trace("not found in this page");
|
||||
continue;
|
||||
auto remove_iter = ranges::remove_if(cur_all_opers, [&](const infrast::Oper& rhs) -> bool {
|
||||
return rhs.mood_ratio < m_mood_threshold;
|
||||
}).begin();
|
||||
cur_all_opers.erase(remove_iter, cur_all_opers.end());
|
||||
Log.trace("after mood filter, opers size:", cur_all_opers.size());
|
||||
for (auto opt_iter = m_optimal_combs.begin(); opt_iter != m_optimal_combs.end();) {
|
||||
Log.trace("to find", opt_iter->skills.begin()->names.front());
|
||||
auto find_iter = ranges::find_if(cur_all_opers, [&](const infrast::Oper& lhs) -> bool {
|
||||
if (lhs.skills != opt_iter->skills) {
|
||||
return false;
|
||||
}
|
||||
Log.trace("found in this page");
|
||||
// 这种情况可能是需要选择两个同样的技能,上一次循环选了一个,但是没有把滑出当前页面,本次又识别到了这个已选择的人
|
||||
if (find_iter->selected == true) {
|
||||
if (cur_max_num_of_opers != 1) {
|
||||
cur_all_opers.erase(find_iter);
|
||||
Log.trace("skill matched, but it's selected, pass");
|
||||
continue;
|
||||
}
|
||||
// 但是如果当前设施只有一个位置,即不存在“上次循环”的情况,说明是清除干员按钮没点到
|
||||
if (opt_iter->name_filter.empty()) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
m_ctrler->click(find_iter->rect);
|
||||
}
|
||||
{
|
||||
auto avlb_iter = ranges::find_if(m_all_available_opers,
|
||||
[&](const infrast::Oper& lhs) -> bool {
|
||||
int dist = HashImageAnalyzer::hamming(lhs.face_hash, find_iter->face_hash);
|
||||
Log.debug("opers_choose | face hash dist", dist);
|
||||
return dist < face_hash_thres;
|
||||
}
|
||||
);
|
||||
if (avlb_iter != m_all_available_opers.cend()) {
|
||||
m_all_available_opers.erase(avlb_iter);
|
||||
}
|
||||
else {
|
||||
Log.error("opers_choose | not found oper");
|
||||
OcrWithPreprocessImageAnalyzer name_analyzer(lhs.name_img);
|
||||
name_analyzer.set_replace(Task.get<OcrTaskInfo>("CharsNameOcrReplace")->replace_map);
|
||||
Log.trace("Analyze name filter");
|
||||
if (!name_analyzer.analyze()) {
|
||||
return false;
|
||||
}
|
||||
std::string name = name_analyzer.get_result().front().text;
|
||||
return ranges::find(std::as_const(opt_iter->name_filter), name) != opt_iter->name_filter.cend();
|
||||
}
|
||||
++count;
|
||||
cur_all_opers.erase(find_iter);
|
||||
opt_iter = m_optimal_combs.erase(opt_iter);
|
||||
}
|
||||
if (m_optimal_combs.empty()) {
|
||||
Log.trace(__FUNCTION__, "| count", count, "cur_max_num_of_opers", cur_max_num_of_opers);
|
||||
if (count < cur_max_num_of_opers) {
|
||||
// 这种情况可能是萌新,可用干员人数不足以填满当前设施
|
||||
callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("NotEnoughStaff"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 因为识别完了还要点击,所以这里不能异步滑动
|
||||
swipe_of_operlist();
|
||||
if (find_iter == cur_all_opers.cend()) {
|
||||
++opt_iter;
|
||||
Log.trace("not found in this page");
|
||||
continue;
|
||||
}
|
||||
Log.trace("found in this page");
|
||||
// 这种情况可能是需要选择两个同样的技能,上一次循环选了一个,但是没有把滑出当前页面,本次又识别到了这个已选择的人
|
||||
if (find_iter->selected == true) {
|
||||
if (cur_max_num_of_opers != 1) {
|
||||
cur_all_opers.erase(find_iter);
|
||||
Log.trace("skill matched, but it's selected, pass");
|
||||
continue;
|
||||
}
|
||||
// 但是如果当前设施只有一个位置,即不存在“上次循环”的情况,说明是清除干员按钮没点到
|
||||
}
|
||||
else {
|
||||
m_ctrler->click(find_iter->rect);
|
||||
}
|
||||
{
|
||||
auto avlb_iter = ranges::find_if(m_all_available_opers, [&](const infrast::Oper& lhs) -> bool {
|
||||
int dist = HashImageAnalyzer::hamming(lhs.face_hash, find_iter->face_hash);
|
||||
Log.debug("opers_choose | face hash dist", dist);
|
||||
return dist < face_hash_thres;
|
||||
});
|
||||
if (avlb_iter != m_all_available_opers.cend()) {
|
||||
m_all_available_opers.erase(avlb_iter);
|
||||
}
|
||||
else {
|
||||
Log.error("opers_choose | not found oper");
|
||||
}
|
||||
}
|
||||
++count;
|
||||
cur_all_opers.erase(find_iter);
|
||||
opt_iter = m_optimal_combs.erase(opt_iter);
|
||||
}
|
||||
if (m_optimal_combs.empty()) {
|
||||
Log.trace(__FUNCTION__, "| count", count, "cur_max_num_of_opers", cur_max_num_of_opers);
|
||||
if (count < cur_max_num_of_opers) {
|
||||
// 这种情况可能是萌新,可用干员人数不足以填满当前设施
|
||||
callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("NotEnoughStaff"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 因为识别完了还要点击,所以这里不能异步滑动
|
||||
swipe_of_operlist();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -582,8 +565,7 @@ bool asst::InfrastProductionTask::use_drone()
|
||||
return task_temp.run();
|
||||
}
|
||||
|
||||
asst::infrast::SkillsComb
|
||||
asst::InfrastProductionTask::efficient_regex_calc(
|
||||
asst::infrast::SkillsComb asst::InfrastProductionTask::efficient_regex_calc(
|
||||
std::unordered_set<infrast::Skill> skills) const
|
||||
{
|
||||
infrast::SkillsComb comb(std::move(skills));
|
||||
|
||||
@@ -26,8 +26,7 @@ namespace asst
|
||||
bool use_drone();
|
||||
void set_product(std::string product_name) noexcept;
|
||||
|
||||
infrast::SkillsComb efficient_regex_calc(
|
||||
std::unordered_set<infrast::Skill> skills) const;
|
||||
infrast::SkillsComb efficient_regex_calc(std::unordered_set<infrast::Skill> skills) const;
|
||||
|
||||
std::string m_product;
|
||||
std::string m_uses_of_drones;
|
||||
|
||||
@@ -46,7 +46,8 @@ bool asst::InfrastReceptionTask::close_end_of_clue_exchange()
|
||||
|
||||
bool asst::InfrastReceptionTask::get_clue()
|
||||
{
|
||||
ProcessTask task_temp(*this, { "InfrastClueSelfNew", "InfrastClueFriendNew", "InfrastClueSelfMaybeFull", "ReceptionFlag" });
|
||||
ProcessTask task_temp(
|
||||
*this, { "InfrastClueSelfNew", "InfrastClueFriendNew", "InfrastClueSelfMaybeFull", "ReceptionFlag" });
|
||||
return task_temp.set_retry_times(ProcessTask::RetryTimesDefault).run();
|
||||
}
|
||||
|
||||
@@ -54,9 +55,7 @@ bool asst::InfrastReceptionTask::use_clue()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const static std::string clue_vacancy = "InfrastClueVacancy";
|
||||
const static std::vector<std::string> clue_suffix = {
|
||||
"No1", "No2", "No3", "No4", "No5", "No6", "No7"
|
||||
};
|
||||
const static std::vector<std::string> clue_suffix = { "No1", "No2", "No3", "No4", "No5", "No6", "No7" };
|
||||
|
||||
proc_clue_vacancy();
|
||||
if (unlock_clue_exchange()) {
|
||||
@@ -69,8 +68,7 @@ bool asst::InfrastReceptionTask::use_clue()
|
||||
InfrastClueVacancyImageAnalyzer vacancy_analyzer(image);
|
||||
|
||||
vacancy_analyzer.set_to_be_analyzed(clue_suffix);
|
||||
if (!vacancy_analyzer.analyze()) {
|
||||
}
|
||||
if (!vacancy_analyzer.analyze()) {}
|
||||
const auto& vacancy = vacancy_analyzer.get_vacancy();
|
||||
for (const auto& id : vacancy | views::keys) {
|
||||
Log.trace("InfrastReceptionTask | Vacancy", id);
|
||||
@@ -93,9 +91,7 @@ bool asst::InfrastReceptionTask::proc_clue_vacancy()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const static std::string clue_vacancy = "InfrastClueVacancy";
|
||||
const static std::vector<std::string> clue_suffix = {
|
||||
"No1", "No2", "No3", "No4", "No5", "No6", "No7"
|
||||
};
|
||||
const static std::vector<std::string> clue_suffix = { "No1", "No2", "No3", "No4", "No5", "No6", "No7" };
|
||||
|
||||
cv::Mat image = m_ctrler->get_image();
|
||||
for (const std::string& clue : clue_suffix) {
|
||||
@@ -116,7 +112,7 @@ bool asst::InfrastReceptionTask::proc_clue_vacancy()
|
||||
sleep(delay);
|
||||
|
||||
// 识别右边列表中的线索,然后用最底下的那个(一般都是剩余时间最短的)
|
||||
//swipe_to_the_bottom_of_clue_list_on_the_right();
|
||||
// swipe_to_the_bottom_of_clue_list_on_the_right();
|
||||
image = m_ctrler->get_image();
|
||||
InfrastClueImageAnalyzer clue_analyzer(image);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ bool asst::InfrastSmileyImageAnalyzer::analyze()
|
||||
}
|
||||
auto& res = mm_analyzer.get_result();
|
||||
for (const MatchRect& mr : res) {
|
||||
temp_result.emplace_back(infrast::Smiley{ type, mr.rect });
|
||||
temp_result.emplace_back(infrast::Smiley { type, mr.rect });
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(m_image_draw, utils::make_rect<cv::Rect>(mr.rect), cv::Scalar(0, 0, 255), 2);
|
||||
#endif
|
||||
|
||||
@@ -13,10 +13,7 @@ namespace asst
|
||||
|
||||
virtual bool analyze() override;
|
||||
|
||||
auto get_result() const noexcept -> const std::vector<infrast::Smiley>&
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
auto get_result() const noexcept -> const std::vector<infrast::Smiley>& { return m_result; }
|
||||
|
||||
protected:
|
||||
std::vector<infrast::Smiley> m_result;
|
||||
|
||||
@@ -2,29 +2,29 @@
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
#include "ProcessTask.h"
|
||||
#include "DronesForShamareTaskPlugin.h"
|
||||
#include "InfrastControlTask.h"
|
||||
#include "InfrastDormTask.h"
|
||||
#include "InfrastInfoTask.h"
|
||||
#include "InfrastMfgTask.h"
|
||||
#include "InfrastTradeTask.h"
|
||||
#include "InfrastPowerTask.h"
|
||||
#include "InfrastControlTask.h"
|
||||
#include "InfrastReceptionTask.h"
|
||||
#include "InfrastOfficeTask.h"
|
||||
#include "InfrastDormTask.h"
|
||||
#include "DronesForShamareTaskPlugin.h"
|
||||
#include "InfrastPowerTask.h"
|
||||
#include "InfrastReceptionTask.h"
|
||||
#include "InfrastTradeTask.h"
|
||||
#include "ProcessTask.h"
|
||||
#include "ReplenishOriginiumShardTaskPlugin.h"
|
||||
|
||||
asst::InfrastTask::InfrastTask(const AsstCallback& callback, void* callback_arg)
|
||||
: PackageTask(callback, callback_arg, TaskType),
|
||||
m_infrast_begin_task_ptr(std::make_shared<ProcessTask>(callback, callback_arg, TaskType)),
|
||||
m_info_task_ptr(std::make_shared<InfrastInfoTask>(callback, callback_arg, TaskType)),
|
||||
m_mfg_task_ptr(std::make_shared<InfrastMfgTask>(callback, callback_arg, TaskType)),
|
||||
m_trade_task_ptr(std::make_shared<InfrastTradeTask>(callback, callback_arg, TaskType)),
|
||||
m_power_task_ptr(std::make_shared<InfrastPowerTask>(callback, callback_arg, TaskType)),
|
||||
m_control_task_ptr(std::make_shared<InfrastControlTask>(callback, callback_arg, TaskType)),
|
||||
m_reception_task_ptr(std::make_shared<InfrastReceptionTask>(callback, callback_arg, TaskType)),
|
||||
m_office_task_ptr(std::make_shared<InfrastOfficeTask>(callback, callback_arg, TaskType)),
|
||||
m_dorm_task_ptr(std::make_shared<InfrastDormTask>(callback, callback_arg, TaskType))
|
||||
m_infrast_begin_task_ptr(std::make_shared<ProcessTask>(callback, callback_arg, TaskType)),
|
||||
m_info_task_ptr(std::make_shared<InfrastInfoTask>(callback, callback_arg, TaskType)),
|
||||
m_mfg_task_ptr(std::make_shared<InfrastMfgTask>(callback, callback_arg, TaskType)),
|
||||
m_trade_task_ptr(std::make_shared<InfrastTradeTask>(callback, callback_arg, TaskType)),
|
||||
m_power_task_ptr(std::make_shared<InfrastPowerTask>(callback, callback_arg, TaskType)),
|
||||
m_control_task_ptr(std::make_shared<InfrastControlTask>(callback, callback_arg, TaskType)),
|
||||
m_reception_task_ptr(std::make_shared<InfrastReceptionTask>(callback, callback_arg, TaskType)),
|
||||
m_office_task_ptr(std::make_shared<InfrastOfficeTask>(callback, callback_arg, TaskType)),
|
||||
m_dorm_task_ptr(std::make_shared<InfrastDormTask>(callback, callback_arg, TaskType))
|
||||
{
|
||||
m_infrast_begin_task_ptr->set_tasks({ "InfrastBegin" });
|
||||
m_trade_task_ptr->register_plugin<DronesForShamareTaskPlugin>()->set_retry_times(0);
|
||||
@@ -41,9 +41,7 @@ bool asst::InfrastTask::set_params(const json::value& params)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto append_infrast_begin = [&]() {
|
||||
m_subtasks.emplace_back(m_infrast_begin_task_ptr);
|
||||
};
|
||||
auto append_infrast_begin = [&]() { m_subtasks.emplace_back(m_infrast_begin_task_ptr); };
|
||||
|
||||
m_subtasks.clear();
|
||||
append_infrast_begin();
|
||||
|
||||
@@ -22,7 +22,8 @@ bool asst::ItemConfiger::parse(const json::value& json)
|
||||
m_ordered_material_item_id.clear();
|
||||
m_ordered_material_item_id.reserve(material_sortid.size());
|
||||
ranges::copy(material_sortid | views::keys, std::back_inserter(m_ordered_material_item_id));
|
||||
ranges::sort(m_ordered_material_item_id, std::less{}, [&](const std::string& name) -> int { return material_sortid[name]; });
|
||||
ranges::sort(m_ordered_material_item_id, std::less {},
|
||||
[&](const std::string& name) -> int { return material_sortid[name]; });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ namespace asst
|
||||
static const std::string unknown = "Unknown";
|
||||
return unknown;
|
||||
}
|
||||
if (auto iter = m_item_name.find(id);
|
||||
iter != m_item_name.cend()) {
|
||||
if (auto iter = m_item_name.find(id); iter != m_item_name.cend()) {
|
||||
return iter->second;
|
||||
}
|
||||
else {
|
||||
@@ -27,14 +26,8 @@ namespace asst
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
const auto& get_all_item_id() const noexcept
|
||||
{
|
||||
return m_all_item_id;
|
||||
}
|
||||
const auto& get_ordered_material_item_id() const noexcept
|
||||
{
|
||||
return m_ordered_material_item_id;
|
||||
}
|
||||
const auto& get_all_item_id() const noexcept { return m_all_item_id; }
|
||||
const auto& get_ordered_material_item_id() const noexcept { return m_ordered_material_item_id; }
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "AsstRanges.hpp"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Version.h"
|
||||
|
||||
namespace asst
|
||||
@@ -18,10 +18,7 @@ namespace asst
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
~Logger()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
~Logger() { flush(); }
|
||||
|
||||
Logger(const Logger&) = delete;
|
||||
Logger(Logger&&) = delete;
|
||||
@@ -137,19 +134,15 @@ namespace asst
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buff, buff_len,
|
||||
#else // ! _MSC_VER
|
||||
#else // ! _MSC_VER
|
||||
sprintf(buff,
|
||||
#endif // END _MSC_VER
|
||||
"[%s][%s][Px%x][Tx%lx]",
|
||||
asst::utils::get_format_time().c_str(),
|
||||
level.data(), _getpid(), ::GetCurrentThreadId()
|
||||
);
|
||||
#else // ! _WIN32
|
||||
sprintf(buff, "[%s][%s][Px%x][Tx%lx]",
|
||||
asst::utils::get_format_time().c_str(),
|
||||
level.data(), getpid(), (unsigned long)(std::hash<std::thread::id>{}(std::this_thread::get_id()))
|
||||
);
|
||||
#endif // END _WIN32
|
||||
#endif // END _MSC_VER
|
||||
"[%s][%s][Px%x][Tx%lx]", asst::utils::get_format_time().c_str(), level.data(), _getpid(),
|
||||
::GetCurrentThreadId());
|
||||
#else // ! _WIN32
|
||||
sprintf(buff, "[%s][%s][Px%x][Tx%lx]", asst::utils::get_format_time().c_str(), level.data(), getpid(),
|
||||
(unsigned long)(std::hash<std::thread::id> {}(std::this_thread::get_id())));
|
||||
#endif // END _WIN32
|
||||
|
||||
if (!m_ofs || !m_ofs.is_open()) {
|
||||
m_ofs = std::ofstream(m_log_filename, std::ios::out | std::ios::app);
|
||||
@@ -166,20 +159,23 @@ namespace asst
|
||||
}
|
||||
|
||||
template <typename Stream, typename T, typename Enable = void>
|
||||
struct has_stream_insertion_operator : std::false_type {};
|
||||
struct has_stream_insertion_operator : std::false_type
|
||||
{};
|
||||
|
||||
template <typename Stream, typename T>
|
||||
struct has_stream_insertion_operator<
|
||||
Stream, T,
|
||||
std::void_t<decltype(std::declval<Stream&>() << std::declval<T>())>>
|
||||
: std::true_type {};
|
||||
struct has_stream_insertion_operator<Stream, T,
|
||||
std::void_t<decltype(std::declval<Stream&>() << std::declval<T>())>>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
template <bool ToAnsi, typename Stream, typename T>
|
||||
static Stream& stream_put(Stream& s, T&& v)
|
||||
{
|
||||
if constexpr (std::is_constructible_v<std::string, T>) {
|
||||
if constexpr (ToAnsi) s << utils::utf8_to_ansi(std::forward<T>(v));
|
||||
else s << std::string(std::forward<T>(v));
|
||||
if constexpr (ToAnsi)
|
||||
s << utils::utf8_to_ansi(std::forward<T>(v));
|
||||
else
|
||||
s << std::string(std::forward<T>(v));
|
||||
return s;
|
||||
}
|
||||
else if constexpr (has_stream_insertion_operator<Stream, T>::value) {
|
||||
@@ -188,7 +184,7 @@ namespace asst
|
||||
}
|
||||
else if constexpr (ranges::input_range<T>) {
|
||||
s << "[";
|
||||
std::string_view comma{};
|
||||
std::string_view comma {};
|
||||
for (const auto& elem : std::forward<T>(v)) {
|
||||
s << comma;
|
||||
stream_put<ToAnsi>(s, elem);
|
||||
@@ -211,7 +207,7 @@ namespace asst
|
||||
struct stream_put_line_impl;
|
||||
|
||||
template <bool ToAnsi, typename Stream>
|
||||
struct stream_put_line_impl <ToAnsi, Stream>
|
||||
struct stream_put_line_impl<ToAnsi, Stream>
|
||||
{
|
||||
static constexpr Stream& apply(Stream& s)
|
||||
{
|
||||
@@ -258,8 +254,7 @@ namespace asst
|
||||
{
|
||||
public:
|
||||
explicit LoggerAux(std::string func_name)
|
||||
: m_func_name(std::move(func_name)),
|
||||
m_start_time(std::chrono::steady_clock::now())
|
||||
: m_func_name(std::move(func_name)), m_start_time(std::chrono::steady_clock::now())
|
||||
{
|
||||
Logger::get_instance().trace(m_func_name, "| enter");
|
||||
}
|
||||
@@ -273,12 +268,13 @@ namespace asst
|
||||
LoggerAux(LoggerAux&&) = default;
|
||||
LoggerAux& operator=(const LoggerAux&) = default;
|
||||
LoggerAux& operator=(LoggerAux&&) = default;
|
||||
|
||||
private:
|
||||
std::string m_func_name;
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start_time;
|
||||
};
|
||||
|
||||
#define _Cat_(a, b) a ## b
|
||||
#define _Cat_(a, b) a##b
|
||||
#define _Cat(a, b) _Cat_(a, b)
|
||||
#define _CatVarNameWithLine(Var) _Cat(Var, __LINE__)
|
||||
|
||||
@@ -286,4 +282,4 @@ namespace asst
|
||||
#define LogTraceScope LoggerAux _CatVarNameWithLine(_func_aux_)
|
||||
#define LogTraceFunction LogTraceScope(__FUNCTION__)
|
||||
#define LogTraceFunctionWithArgs // how to do this?, like LogTraceScope(__FUNCTION__, __FUNCTION_ALL_ARGS__)
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "MallTask.h"
|
||||
|
||||
#include "ProcessTask.h"
|
||||
#include "CreditShoppingTask.h"
|
||||
#include "ProcessTask.h"
|
||||
|
||||
asst::MallTask::MallTask(const AsstCallback& callback, void* callback_arg)
|
||||
: PackageTask(callback, callback_arg, TaskType),
|
||||
m_mall_task_ptr(std::make_shared<ProcessTask>(callback, callback_arg, TaskType)),
|
||||
m_shopping_first_task_ptr(std::make_shared<CreditShoppingTask>(callback, callback_arg, TaskType)),
|
||||
m_shopping_task_ptr(std::make_shared<CreditShoppingTask>(callback, callback_arg, TaskType))
|
||||
m_mall_task_ptr(std::make_shared<ProcessTask>(callback, callback_arg, TaskType)),
|
||||
m_shopping_first_task_ptr(std::make_shared<CreditShoppingTask>(callback, callback_arg, TaskType)),
|
||||
m_shopping_task_ptr(std::make_shared<CreditShoppingTask>(callback, callback_arg, TaskType))
|
||||
{
|
||||
m_mall_task_ptr->set_tasks({ "MallBegin" });
|
||||
m_shopping_first_task_ptr->set_enable(false).set_retry_times(1);
|
||||
@@ -26,8 +26,7 @@ bool asst::MallTask::set_params(const json::value& params)
|
||||
if (auto buy_first_opt = params.find<json::array>("buy_first")) {
|
||||
std::vector<std::string> buy_first;
|
||||
for (auto& name : buy_first_opt.value()) {
|
||||
if (std::string name_str = name.as_string();
|
||||
!name_str.empty()) {
|
||||
if (std::string name_str = name.as_string(); !name_str.empty()) {
|
||||
buy_first.emplace_back(name_str);
|
||||
}
|
||||
}
|
||||
@@ -46,8 +45,7 @@ bool asst::MallTask::set_params(const json::value& params)
|
||||
if (auto blacklist_opt = params.find<json::array>("blacklist")) {
|
||||
std::vector<std::string> shopping_list;
|
||||
for (auto& name : blacklist_opt.value()) {
|
||||
if (std::string name_str = name.as_string();
|
||||
!name_str.empty()) {
|
||||
if (std::string name_str = name.as_string(); !name_str.empty()) {
|
||||
shopping_list.emplace_back(name.as_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace asst
|
||||
virtual bool set_params(const json::value& params) override;
|
||||
|
||||
static constexpr const char* TaskType = "Mall";
|
||||
|
||||
private:
|
||||
std::shared_ptr<ProcessTask> m_mall_task_ptr = nullptr;
|
||||
std::shared_ptr<CreditShoppingTask> m_shopping_first_task_ptr = nullptr;
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
|
||||
asst::MatchImageAnalyzer::MatchImageAnalyzer(const cv::Mat& image, const Rect& roi, std::string templ_name, double templ_thres)
|
||||
: AbstractImageAnalyzer(image, roi),
|
||||
m_templ_name(std::move(templ_name)),
|
||||
m_templ_thres(templ_thres)
|
||||
asst::MatchImageAnalyzer::MatchImageAnalyzer(const cv::Mat& image, const Rect& roi, std::string templ_name,
|
||||
double templ_thres)
|
||||
: AbstractImageAnalyzer(image, roi), m_templ_name(std::move(templ_name)), m_templ_thres(templ_thres)
|
||||
{}
|
||||
|
||||
bool asst::MatchImageAnalyzer::analyze()
|
||||
@@ -117,9 +116,8 @@ bool asst::MatchImageAnalyzer::match_templ(const cv::Mat templ)
|
||||
|
||||
cv::Mat image_roi = m_image(utils::make_rect<cv::Rect>(m_roi));
|
||||
if (templ.cols > image_roi.cols || templ.rows > image_roi.rows) {
|
||||
Log.error("templ size is too large", m_templ_name,
|
||||
"image_roi size:", image_roi.cols, image_roi.rows,
|
||||
"templ size:", templ.cols, templ.rows);
|
||||
Log.error("templ size is too large", m_templ_name, "image_roi size:", image_roi.cols, image_roi.rows,
|
||||
"templ size:", templ.cols, templ.rows);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -146,7 +144,8 @@ bool asst::MatchImageAnalyzer::match_templ(const cv::Mat templ)
|
||||
max_val = 0;
|
||||
}
|
||||
if (max_val > m_templ_thres * 0.7) { // 得分太低的肯定不对,没必要打印
|
||||
Log.trace("match_templ |", m_templ_name, "score:", max_val, "rect:", rect.to_string(), "roi:", m_roi.to_string());
|
||||
Log.trace("match_templ |", m_templ_name, "score:", max_val, "rect:", rect.to_string(),
|
||||
"roi:", m_roi.to_string());
|
||||
}
|
||||
|
||||
if (m_templ_thres <= max_val && max_val < 2.0) {
|
||||
|
||||
@@ -9,10 +9,9 @@
|
||||
#include "Resource.h"
|
||||
#include "TaskData.h"
|
||||
|
||||
asst::MultiMatchImageAnalyzer::MultiMatchImageAnalyzer(const cv::Mat& image, const Rect& roi, std::string templ_name, double templ_thres)
|
||||
: AbstractImageAnalyzer(image, roi),
|
||||
m_templ_name(std::move(templ_name)),
|
||||
m_templ_thres(templ_thres)
|
||||
asst::MultiMatchImageAnalyzer::MultiMatchImageAnalyzer(const cv::Mat& image, const Rect& roi, std::string templ_name,
|
||||
double templ_thres)
|
||||
: AbstractImageAnalyzer(image, roi), m_templ_name(std::move(templ_name)), m_templ_thres(templ_thres)
|
||||
{}
|
||||
|
||||
bool asst::MultiMatchImageAnalyzer::analyze()
|
||||
@@ -32,29 +31,27 @@ bool asst::MultiMatchImageAnalyzer::analyze()
|
||||
void asst::MultiMatchImageAnalyzer::sort_result_horizontal()
|
||||
{
|
||||
// 按位置排个序
|
||||
ranges::sort(m_result,
|
||||
[](const MatchRect& lhs, const MatchRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
});
|
||||
ranges::sort(m_result, [](const MatchRect& lhs, const MatchRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void asst::MultiMatchImageAnalyzer::sort_result_vertical()
|
||||
{
|
||||
// 按位置排个序
|
||||
ranges::sort(m_result,
|
||||
[](const MatchRect& lhs, const MatchRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.x - rhs.rect.x) < 5) { // x差距较小则理解为是同一排的,按y排序
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
});
|
||||
ranges::sort(m_result, [](const MatchRect& lhs, const MatchRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.x - rhs.rect.x) < 5) { // x差距较小则理解为是同一排的,按y排序
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void asst::MultiMatchImageAnalyzer::set_mask_range(int lower, int upper) noexcept
|
||||
@@ -106,9 +103,8 @@ bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat templ)
|
||||
cv::Mat image_roi = m_image(utils::make_rect<cv::Rect>(m_roi));
|
||||
|
||||
if (templ.cols > image_roi.cols || templ.rows > image_roi.rows) {
|
||||
Log.error("templ size is too large", m_templ_name,
|
||||
"image_roi size:", image_roi.cols, image_roi.rows,
|
||||
"templ size:", templ.cols, templ.rows);
|
||||
Log.error("templ size is too large", m_templ_name, "image_roi size:", image_roi.cols, image_roi.rows,
|
||||
"templ size:", templ.cols, templ.rows);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -118,7 +114,7 @@ bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat templ)
|
||||
else {
|
||||
cv::Mat mask;
|
||||
cv::cvtColor(templ, mask, cv::COLOR_BGR2GRAY);
|
||||
//cv::threshold(mask, mask, m_mask_range.first, 255, cv::THRESH_BINARY);
|
||||
// cv::threshold(mask, mask, m_mask_range.first, 255, cv::THRESH_BINARY);
|
||||
cv::inRange(mask, m_mask_range.first, m_mask_range.second, mask);
|
||||
cv::matchTemplate(image_roi, templ, matched, cv::TM_CCOEFF_NORMED, mask);
|
||||
}
|
||||
@@ -133,7 +129,8 @@ bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat templ)
|
||||
// 如果有两个点离得太近,只取里面得分高的那个
|
||||
// 一般相邻的都是刚刚push进去的,这里倒序快一点
|
||||
for (auto& iter : ranges::reverse_view(m_result)) {
|
||||
if (std::abs(j + m_roi.x - iter.rect.x) < mini_distance && std::abs(i + m_roi.y - iter.rect.y) < mini_distance) {
|
||||
if (std::abs(j + m_roi.x - iter.rect.x) < mini_distance &&
|
||||
std::abs(i + m_roi.y - iter.rect.y) < mini_distance) {
|
||||
if (iter.score < value) {
|
||||
iter.rect = rect;
|
||||
iter.score = value;
|
||||
@@ -152,7 +149,8 @@ bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat templ)
|
||||
#ifdef ASST_DEBUG
|
||||
for (const auto& rect : m_result) {
|
||||
cv::rectangle(m_image_draw, utils::make_rect<cv::Rect>(rect.rect), cv::Scalar(0, 0, 255), 2);
|
||||
cv::putText(m_image_draw, std::to_string(rect.score), cv::Point(rect.rect.x, rect.rect.y), 1, 1, cv::Scalar(0, 0, 255));
|
||||
cv::putText(m_image_draw, std::to_string(rect.score), cv::Point(rect.rect.x, rect.rect.y), 1, 1,
|
||||
cv::Scalar(0, 0, 255));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ bool asst::OcrImageAnalyzer::analyze()
|
||||
|
||||
m_ocr_result = Resrc.ocr().recognize(m_image, m_roi, all_pred, m_without_det);
|
||||
|
||||
//log.trace("ocr result", m_ocr_result);
|
||||
// log.trace("ocr result", m_ocr_result);
|
||||
return !m_ocr_result.empty();
|
||||
}
|
||||
|
||||
@@ -161,16 +161,14 @@ const std::vector<asst::TextRect>& asst::OcrImageAnalyzer::get_result() const no
|
||||
void asst::OcrImageAnalyzer::sort_result_horizontal()
|
||||
{
|
||||
// 按位置排个序
|
||||
ranges::sort(get_result(),
|
||||
[](const TextRect& lhs, const TextRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
ranges::sort(get_result(), [](const TextRect& lhs, const TextRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
);
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void asst::OcrImageAnalyzer::sort_result_vertical()
|
||||
@@ -180,21 +178,19 @@ void asst::OcrImageAnalyzer::sort_result_vertical()
|
||||
// |1 3|
|
||||
// |2 4|
|
||||
// +---+
|
||||
ranges::sort(get_result(),
|
||||
[](const TextRect& lhs, const TextRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.x - rhs.rect.x) < 5) { // x差距较小则理解为是同一排的,按y排序
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
ranges::sort(get_result(), [](const TextRect& lhs, const TextRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.x - rhs.rect.x) < 5) { // x差距较小则理解为是同一排的,按y排序
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
);
|
||||
else {
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void asst::OcrImageAnalyzer::sort_result_by_score()
|
||||
{
|
||||
ranges::sort(get_result(), std::greater{}, std::mem_fn(&TextRect::score));
|
||||
ranges::sort(get_result(), std::greater {}, std::mem_fn(&TextRect::score));
|
||||
}
|
||||
|
||||
void asst::OcrImageAnalyzer::sort_result_by_required()
|
||||
@@ -210,16 +206,15 @@ void asst::OcrImageAnalyzer::sort_result_by_required()
|
||||
|
||||
auto& result = get_result();
|
||||
// 不在 m_required 中的将被排在最后
|
||||
ranges::sort(result,
|
||||
[&req_cache](const auto& lhs, const auto& rhs) -> bool {
|
||||
size_t lvalue = req_cache[lhs.text];
|
||||
size_t rvalue = req_cache[rhs.text];
|
||||
if (lvalue == 0) {
|
||||
return false;
|
||||
}
|
||||
else if (rvalue == 0) {
|
||||
return true;
|
||||
}
|
||||
return lvalue < rvalue;
|
||||
});
|
||||
ranges::sort(result, [&req_cache](const auto& lhs, const auto& rhs) -> bool {
|
||||
size_t lvalue = req_cache[lhs.text];
|
||||
size_t rvalue = req_cache[rhs.text];
|
||||
if (lvalue == 0) {
|
||||
return false;
|
||||
}
|
||||
else if (rvalue == 0) {
|
||||
return true;
|
||||
}
|
||||
return lvalue < rvalue;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ namespace asst
|
||||
|
||||
void filter(const TextRectProc& filter_func);
|
||||
|
||||
virtual void sort_result_horizontal(); // 按位置排序,左上角的排在前面,右上角在左下角前面
|
||||
virtual void sort_result_vertical(); // 按位置排序,左上角的排在前面,左下角在右上角前面
|
||||
virtual void sort_result_by_score(); // 按分数排序,得分最高的在前面
|
||||
virtual void sort_result_horizontal(); // 按位置排序,左上角的排在前面,右上角在左下角前面
|
||||
virtual void sort_result_vertical(); // 按位置排序,左上角的排在前面,左下角在右上角前面
|
||||
virtual void sort_result_by_score(); // 按分数排序,得分最高的在前面
|
||||
virtual void sort_result_by_required(); // 按传入的需求数组排序,传入的在前面结果接在前面
|
||||
|
||||
void set_required(std::vector<std::string> required) noexcept;
|
||||
|
||||
@@ -14,7 +14,7 @@ asst::OcrPack::OcrPack()
|
||||
for (size_t i = 0; i != MaxBoxSize; ++i) {
|
||||
constexpr static size_t MaxTextSize = 1024;
|
||||
*(m_strs_buffer + i) = new char[MaxTextSize];
|
||||
//memset(*(m_strs_buffer + i), 0, MaxTextSize);
|
||||
// memset(*(m_strs_buffer + i), 0, MaxTextSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ bool asst::OcrPack::load(const std::string& dir)
|
||||
}
|
||||
|
||||
constexpr static auto DetName = "/det";
|
||||
//constexpr static const char* ClsName = "/cls";
|
||||
// constexpr static const char* ClsName = "/cls";
|
||||
constexpr static auto RecName = "/rec";
|
||||
constexpr static auto KeysName = "/ppocr_keys_v1.txt";
|
||||
|
||||
const std::string dst_filename = dir + DetName;
|
||||
//const std::string cls_filename = dir + ClsName;
|
||||
// const std::string cls_filename = dir + ClsName;
|
||||
const std::string rec_filename = dir + RecName;
|
||||
const std::string keys_filename = dir + KeysName;
|
||||
|
||||
@@ -53,7 +53,8 @@ bool asst::OcrPack::load(const std::string& dir)
|
||||
return m_ocr != nullptr;
|
||||
}
|
||||
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const asst::TextRectProc& pred, bool without_det)
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const asst::TextRectProc& pred,
|
||||
bool without_det)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -64,13 +65,12 @@ std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const
|
||||
|
||||
if (!without_det) {
|
||||
Log.trace("Ocr System");
|
||||
PaddleOcrSystem(m_ocr, buf.data(), buf.size(),
|
||||
false, m_boxes_buffer, m_strs_buffer, m_scores_buffer, &size, nullptr, nullptr);
|
||||
PaddleOcrSystem(m_ocr, buf.data(), buf.size(), false, m_boxes_buffer, m_strs_buffer, m_scores_buffer, &size,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
else {
|
||||
Log.trace("Ocr Rec");
|
||||
PaddleOcrRec(m_ocr, buf.data(), buf.size(),
|
||||
m_strs_buffer, m_scores_buffer, &size, nullptr, nullptr);
|
||||
PaddleOcrRec(m_ocr, buf.data(), buf.size(), m_strs_buffer, m_scores_buffer, &size, nullptr, nullptr);
|
||||
}
|
||||
|
||||
std::vector<TextRect> result;
|
||||
@@ -102,7 +102,7 @@ std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const
|
||||
score = 0;
|
||||
}
|
||||
|
||||
TextRect tr{ score, rect, text };
|
||||
TextRect tr { score, rect, text };
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(draw, utils::make_rect<cv::Rect>(rect), cv::Scalar(0, 0, 255), 2);
|
||||
#endif
|
||||
@@ -118,7 +118,8 @@ std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const Rect& roi, const asst::TextRectProc& pred, bool without_det)
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const Rect& roi,
|
||||
const asst::TextRectProc& pred, bool without_det)
|
||||
{
|
||||
auto rect_cor = [&roi, &pred, &without_det](TextRect& tr) -> bool {
|
||||
if (without_det) {
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace asst
|
||||
class OcrPack final : public AbstractResource
|
||||
{
|
||||
constexpr static size_t MaxBoxSize = 128;
|
||||
|
||||
public:
|
||||
using AbstractResource::AbstractResource;
|
||||
OcrPack();
|
||||
@@ -23,8 +24,10 @@ namespace asst
|
||||
|
||||
virtual bool load(const std::string& dir) override;
|
||||
|
||||
std::vector<TextRect> recognize(const cv::Mat& image, const TextRectProc& pred = nullptr, bool without_det = false);
|
||||
std::vector<TextRect> recognize(const cv::Mat& image, const Rect& roi, const TextRectProc& pred = nullptr, bool without_det = false);
|
||||
std::vector<TextRect> recognize(const cv::Mat& image, const TextRectProc& pred = nullptr,
|
||||
bool without_det = false);
|
||||
std::vector<TextRect> recognize(const cv::Mat& image, const Rect& roi, const TextRectProc& pred = nullptr,
|
||||
bool without_det = false);
|
||||
|
||||
private:
|
||||
paddle_ocr_t* m_ocr = nullptr;
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
#include "TaskData.h"
|
||||
|
||||
asst::OcrWithFlagTemplImageAnalyzer::OcrWithFlagTemplImageAnalyzer(const cv::Mat& image)
|
||||
: OcrWithPreprocessImageAnalyzer(image),
|
||||
m_multi_match_image_analyzer(image)
|
||||
: OcrWithPreprocessImageAnalyzer(image), m_multi_match_image_analyzer(image)
|
||||
{}
|
||||
|
||||
asst::OcrWithFlagTemplImageAnalyzer::OcrWithFlagTemplImageAnalyzer(const cv::Mat& image, const Rect& roi)
|
||||
: OcrWithPreprocessImageAnalyzer(image, roi),
|
||||
m_multi_match_image_analyzer(image, roi)
|
||||
: OcrWithPreprocessImageAnalyzer(image, roi), m_multi_match_image_analyzer(image, roi)
|
||||
{}
|
||||
|
||||
void asst::OcrWithFlagTemplImageAnalyzer::set_image(const cv::Mat image)
|
||||
@@ -39,9 +37,8 @@ bool asst::OcrWithFlagTemplImageAnalyzer::analyze()
|
||||
set_roi(roi);
|
||||
|
||||
if (OcrWithPreprocessImageAnalyzer::analyze()) {
|
||||
m_all_result.insert(m_all_result.end(),
|
||||
std::make_move_iterator(m_ocr_result.begin()),
|
||||
std::make_move_iterator(m_ocr_result.end()));
|
||||
m_all_result.insert(m_all_result.end(), std::make_move_iterator(m_ocr_result.begin()),
|
||||
std::make_move_iterator(m_ocr_result.end()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +50,8 @@ const std::vector<asst::TextRect>& asst::OcrWithFlagTemplImageAnalyzer::get_resu
|
||||
return m_all_result;
|
||||
}
|
||||
|
||||
void asst::OcrWithFlagTemplImageAnalyzer::set_task_info(const std::string& templ_task_name, const std::string&
|
||||
ocr_task_name)
|
||||
void asst::OcrWithFlagTemplImageAnalyzer::set_task_info(const std::string& templ_task_name,
|
||||
const std::string& ocr_task_name)
|
||||
{
|
||||
auto ocr_task_ptr = Task.get<OcrTaskInfo>(ocr_task_name);
|
||||
OcrWithPreprocessImageAnalyzer::set_task_info(*ocr_task_ptr);
|
||||
|
||||
@@ -20,11 +20,11 @@ namespace asst
|
||||
virtual const std::vector<TextRect>& get_result() const noexcept override;
|
||||
virtual std::vector<TextRect>& get_result() noexcept override;
|
||||
|
||||
void set_task_info(const std::string& templ_task_name, const std::string& ocr_task_name); // FIXME: hiding virtual function
|
||||
void set_task_info(const std::string& templ_task_name,
|
||||
const std::string& ocr_task_name); // FIXME: hiding virtual function
|
||||
void set_flag_rect_move(Rect flag_rect_move);
|
||||
|
||||
protected:
|
||||
|
||||
MultiMatchImageAnalyzer m_multi_match_image_analyzer;
|
||||
Rect m_flag_rect_move;
|
||||
std::vector<TextRect> m_all_result;
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace asst
|
||||
|
||||
virtual void set_task_info(std::shared_ptr<TaskInfo> task_ptr) override;
|
||||
virtual void set_task_info(const std::string& task_name) override;
|
||||
|
||||
protected:
|
||||
virtual void set_task_info(OcrTaskInfo task_info) noexcept override;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "PackageTask.h"
|
||||
|
||||
#include "Resource.h"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
|
||||
bool asst::PackageTask::run()
|
||||
{
|
||||
@@ -23,10 +23,7 @@ bool asst::PackageTask::run()
|
||||
continue;
|
||||
}
|
||||
|
||||
task_ptr->set_exit_flag(m_exit_flag)
|
||||
.set_ctrler(m_ctrler)
|
||||
.set_status(m_status)
|
||||
.set_task_id(m_task_id);
|
||||
task_ptr->set_exit_flag(m_exit_flag).set_ctrler(m_ctrler).set_status(m_status).set_task_id(m_task_id);
|
||||
|
||||
if (!task_ptr->run() && !task_ptr->get_ignore_error()) {
|
||||
return false;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "AbstractTask.h"
|
||||
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
namespace json
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
asst::PipelineTask::PipelineTask(const AsstCallback& callback, void* callback_arg)
|
||||
: PackageTask(callback, callback_arg, TaskType),
|
||||
m_task_ptr(std::make_shared<ProcessTask>(callback, callback_arg, TaskType))
|
||||
m_task_ptr(std::make_shared<ProcessTask>(callback, callback_arg, TaskType))
|
||||
{}
|
||||
|
||||
bool asst::PipelineTask::set_params(const json::value& params)
|
||||
|
||||
@@ -7,24 +7,22 @@
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Controller.h"
|
||||
#include "Logger.hpp"
|
||||
#include "ProcessTaskImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
#include "Logger.hpp"
|
||||
#include "RuntimeStatus.h"
|
||||
|
||||
using namespace asst;
|
||||
|
||||
asst::ProcessTask::ProcessTask(const AbstractTask& abs, std::vector<std::string> tasks_name)
|
||||
: AbstractTask(abs),
|
||||
m_raw_tasks_name(std::move(tasks_name))
|
||||
: AbstractTask(abs), m_raw_tasks_name(std::move(tasks_name))
|
||||
{
|
||||
m_task_delay = Resrc.cfg().get_options().task_delay;
|
||||
m_basic_info_cache = json::value();
|
||||
}
|
||||
|
||||
asst::ProcessTask::ProcessTask(AbstractTask&& abs, std::vector<std::string> tasks_name) noexcept
|
||||
: AbstractTask(std::move(abs)),
|
||||
m_raw_tasks_name(std::move(tasks_name))
|
||||
: AbstractTask(std::move(abs)), m_raw_tasks_name(std::move(tasks_name))
|
||||
{
|
||||
m_task_delay = Resrc.cfg().get_options().task_delay;
|
||||
m_basic_info_cache = json::value();
|
||||
@@ -88,11 +86,9 @@ bool ProcessTask::_run()
|
||||
return false;
|
||||
}
|
||||
json::value info = basic_info();
|
||||
info["details"] = json::object{
|
||||
{"to_be_recognized", json::array(m_cur_tasks_name)},
|
||||
{"cur_retry", m_cur_retry},
|
||||
{"retry_times", m_retry_times}
|
||||
};
|
||||
info["details"] = json::object { { "to_be_recognized", json::array(m_cur_tasks_name) },
|
||||
{ "cur_retry", m_cur_retry },
|
||||
{ "retry_times", m_retry_times } };
|
||||
Log.info(info.to_string());
|
||||
|
||||
auto front_task_ptr = Task.get(m_cur_tasks_name.front());
|
||||
@@ -132,18 +128,14 @@ bool ProcessTask::_run()
|
||||
int& exec_times = m_exec_times[cur_name];
|
||||
|
||||
int max_times = m_cur_task_ptr->max_times;
|
||||
if (auto iter = m_times_limit.find(cur_name);
|
||||
iter != m_times_limit.cend()) {
|
||||
if (auto iter = m_times_limit.find(cur_name); iter != m_times_limit.cend()) {
|
||||
max_times = iter->second;
|
||||
}
|
||||
|
||||
if (exec_times >= max_times) {
|
||||
info["what"] = "ExceededLimit";
|
||||
info["details"] = json::object{
|
||||
{ "task", cur_name },
|
||||
{ "exec_times", exec_times },
|
||||
{ "max_times", max_times }
|
||||
};
|
||||
info["details"] =
|
||||
json::object { { "task", cur_name }, { "exec_times", exec_times }, { "max_times", max_times } };
|
||||
Log.info("exec times exceeded the limit", info.to_string());
|
||||
callback(AsstMsg::SubTaskExtraInfo, info);
|
||||
m_cur_tasks_name = m_cur_task_ptr->exceeded_next;
|
||||
@@ -154,13 +146,11 @@ bool ProcessTask::_run()
|
||||
m_cur_retry = 0;
|
||||
++exec_times;
|
||||
|
||||
info["details"] = json::object{
|
||||
{ "task", cur_name },
|
||||
{ "action", static_cast<int>(m_cur_task_ptr->action) },
|
||||
{ "exec_times", exec_times },
|
||||
{ "max_times", max_times },
|
||||
{ "algorithm", static_cast<int>(m_cur_task_ptr->algorithm) }
|
||||
};
|
||||
info["details"] = json::object { { "task", cur_name },
|
||||
{ "action", static_cast<int>(m_cur_task_ptr->action) },
|
||||
{ "exec_times", exec_times },
|
||||
{ "max_times", max_times },
|
||||
{ "algorithm", static_cast<int>(m_cur_task_ptr->algorithm) } };
|
||||
|
||||
callback(AsstMsg::SubTaskStart, info);
|
||||
|
||||
@@ -212,14 +202,14 @@ bool ProcessTask::_run()
|
||||
Log.trace("Task `", m_cur_task_ptr->name, "` reduce `", reduce, "` times to ", v);
|
||||
}
|
||||
else {
|
||||
Log.trace("Task `", m_cur_task_ptr->name, "` attempt to reduce `", reduce, "` times, but it is already 0");
|
||||
Log.trace("Task `", m_cur_task_ptr->name, "` attempt to reduce `", reduce,
|
||||
"` times, but it is already 0");
|
||||
}
|
||||
}
|
||||
|
||||
// 后置固定延时
|
||||
int rear_delay = m_cur_task_ptr->rear_delay;
|
||||
if (auto iter = m_rear_delay.find(cur_name);
|
||||
iter != m_rear_delay.cend()) {
|
||||
if (auto iter = m_rear_delay.find(cur_name); iter != m_rear_delay.cend()) {
|
||||
rear_delay = iter->second;
|
||||
}
|
||||
if (!sleep(rear_delay)) {
|
||||
@@ -265,9 +255,7 @@ bool asst::ProcessTask::on_run_fails()
|
||||
|
||||
json::value asst::ProcessTask::basic_info() const
|
||||
{
|
||||
return AbstractTask::basic_info() | json::object{
|
||||
{ "first", json::array(m_raw_tasks_name) }
|
||||
};
|
||||
return AbstractTask::basic_info() | json::object { { "first", json::array(m_raw_tasks_name) } };
|
||||
}
|
||||
|
||||
void ProcessTask::exec_click_task(const Rect& matched_rect)
|
||||
@@ -279,17 +267,11 @@ void asst::ProcessTask::exec_swipe_task(ProcessTaskAction action)
|
||||
{
|
||||
const auto&& [width, height] = m_ctrler->get_scale_size();
|
||||
|
||||
const static Rect right_rect(
|
||||
static_cast<int>(width * 0.8),
|
||||
static_cast<int>(height * 0.4),
|
||||
static_cast<int>(width * 0.1),
|
||||
static_cast<int>(height * 0.2));
|
||||
const static Rect right_rect(static_cast<int>(width * 0.8), static_cast<int>(height * 0.4),
|
||||
static_cast<int>(width * 0.1), static_cast<int>(height * 0.2));
|
||||
|
||||
const static Rect left_rect(
|
||||
static_cast<int>(width * 0.1),
|
||||
static_cast<int>(height * 0.4),
|
||||
static_cast<int>(width * 0.1),
|
||||
static_cast<int>(height * 0.2));
|
||||
const static Rect left_rect(static_cast<int>(width * 0.1), static_cast<int>(height * 0.4),
|
||||
static_cast<int>(width * 0.1), static_cast<int>(height * 0.2));
|
||||
|
||||
switch (action) {
|
||||
case asst::ProcessTaskAction::SwipeToTheLeft:
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
#include "RuntimeStatus.h"
|
||||
|
||||
asst::ProcessTaskImageAnalyzer::ProcessTaskImageAnalyzer(const cv::Mat& image, std::vector<std::string> tasks_name)
|
||||
: AbstractImageAnalyzer(image),
|
||||
m_tasks_name(std::move(tasks_name))
|
||||
: AbstractImageAnalyzer(image), m_tasks_name(std::move(tasks_name))
|
||||
{}
|
||||
|
||||
asst::ProcessTaskImageAnalyzer::~ProcessTaskImageAnalyzer() = default;
|
||||
@@ -44,7 +43,7 @@ bool asst::ProcessTaskImageAnalyzer::ocr_analyze(const std::shared_ptr<TaskInfo>
|
||||
std::shared_ptr<OcrTaskInfo> ocr_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(task_ptr);
|
||||
|
||||
// 先尝试从缓存的结果里找
|
||||
//for (const TextRect& tr : m_ocr_cache) {
|
||||
// for (const TextRect& tr : m_ocr_cache) {
|
||||
// TextRect temp = tr;
|
||||
// for (const auto& [regex, new_str] : ocr_task_ptr->replace_map) {
|
||||
// temp.text = std::regex_replace(temp.text, std::regex(regex), new_str);
|
||||
@@ -88,7 +87,7 @@ bool asst::ProcessTaskImageAnalyzer::ocr_analyze(const std::shared_ptr<TaskInfo>
|
||||
m_result = ocr_task_ptr;
|
||||
m_result_rect = res.rect;
|
||||
m_status->set_rect(ocr_task_ptr->name, m_result_rect);
|
||||
//m_ocr_cache.insert(m_ocr_cache.end(), ocr_result.begin(), ocr_result.end());
|
||||
// m_ocr_cache.insert(m_ocr_cache.end(), ocr_result.begin(), ocr_result.end());
|
||||
Log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found", res.to_string());
|
||||
}
|
||||
return ret;
|
||||
@@ -96,7 +95,7 @@ bool asst::ProcessTaskImageAnalyzer::ocr_analyze(const std::shared_ptr<TaskInfo>
|
||||
|
||||
void asst::ProcessTaskImageAnalyzer::reset() noexcept
|
||||
{
|
||||
//m_ocr_cache.clear();
|
||||
// m_ocr_cache.clear();
|
||||
m_ocr_analyzer = nullptr;
|
||||
m_match_analyzer = nullptr;
|
||||
}
|
||||
|
||||
@@ -27,14 +27,8 @@ namespace asst
|
||||
void set_tasks(std::vector<std::string> tasks_name);
|
||||
void set_status(std::shared_ptr<RuntimeStatus> status) noexcept;
|
||||
|
||||
std::shared_ptr<TaskInfo> get_result() const noexcept
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
const Rect& get_rect() const noexcept
|
||||
{
|
||||
return m_result_rect;
|
||||
}
|
||||
std::shared_ptr<TaskInfo> get_result() const noexcept { return m_result; }
|
||||
const Rect& get_rect() const noexcept { return m_result_rect; }
|
||||
|
||||
ProcessTaskImageAnalyzer& operator=(const ProcessTaskImageAnalyzer&) = delete;
|
||||
ProcessTaskImageAnalyzer& operator=(ProcessTaskImageAnalyzer&&) = delete;
|
||||
@@ -52,6 +46,6 @@ namespace asst
|
||||
std::shared_ptr<TaskInfo> m_result = nullptr;
|
||||
std::shared_ptr<RuntimeStatus> m_status = nullptr;
|
||||
Rect m_result_rect;
|
||||
//std::vector<TextRect> m_ocr_cache;
|
||||
// std::vector<TextRect> m_ocr_cache;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ bool asst::RecruitConfiger::parse(const json::value& json)
|
||||
}
|
||||
|
||||
// 按干员等级排个序
|
||||
ranges::sort(m_all_opers, std::greater{}, std::mem_fn(&RecruitOperInfo::level));
|
||||
ranges::sort(m_all_opers, std::greater {}, std::mem_fn(&RecruitOperInfo::level));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "AbstractConfiger.h"
|
||||
|
||||
#include "AsstRanges.hpp"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include "AsstRanges.hpp"
|
||||
|
||||
#include "AsstTypes.h"
|
||||
|
||||
@@ -24,15 +24,12 @@ namespace asst
|
||||
bool hidden = false;
|
||||
std::string name_en;
|
||||
|
||||
bool has_tag(const std::string& tag) const
|
||||
{
|
||||
return tags.contains(tag);
|
||||
}
|
||||
bool has_tag(const std::string& tag) const { return tags.contains(tag); }
|
||||
|
||||
friend std::strong_ordering operator<=>(const RecruitOperInfo& lhs, const RecruitOperInfo& rhs)
|
||||
{
|
||||
if (lhs.level != rhs.level) return lhs.level <=> rhs.level; // increment order
|
||||
return rhs.name <=> lhs.name; // decrement order (print reversely)
|
||||
return rhs.name <=> lhs.name; // decrement order (print reversely)
|
||||
}
|
||||
|
||||
friend bool operator==(const RecruitOperInfo& lhs, const RecruitOperInfo& rhs)
|
||||
@@ -54,19 +51,16 @@ namespace asst
|
||||
void update_attributes()
|
||||
{
|
||||
min_level = std::transform_reduce(
|
||||
opers.cbegin(), opers.cend(), 7,
|
||||
[](int a, int b) -> int { return (std::min)(a, b); },
|
||||
std::mem_fn(&RecruitOperInfo::level));
|
||||
opers.cbegin(), opers.cend(), 7, [](int a, int b) -> int { return (std::min)(a, b); },
|
||||
std::mem_fn(&RecruitOperInfo::level));
|
||||
|
||||
max_level = std::transform_reduce(
|
||||
opers.cbegin(), opers.cend(), 0,
|
||||
[](int a, int b) -> int { return (std::max)(a, b); },
|
||||
std::mem_fn(&RecruitOperInfo::level));
|
||||
opers.cbegin(), opers.cend(), 0, [](int a, int b) -> int { return (std::max)(a, b); },
|
||||
std::mem_fn(&RecruitOperInfo::level));
|
||||
|
||||
avg_level = std::transform_reduce(
|
||||
opers.cbegin(), opers.cend(), 0.,
|
||||
std::plus<double>{},
|
||||
std::mem_fn(&RecruitOperInfo::level)) / static_cast<double>(opers.size());
|
||||
avg_level = std::transform_reduce(opers.cbegin(), opers.cend(), 0., std::plus<double> {},
|
||||
std::mem_fn(&RecruitOperInfo::level)) /
|
||||
static_cast<double>(opers.size());
|
||||
}
|
||||
|
||||
// intersection of two recruit combs
|
||||
@@ -95,14 +89,8 @@ namespace asst
|
||||
virtual ~RecruitConfiger() override = default;
|
||||
constexpr static int CorrectNumberOfTags = 5;
|
||||
|
||||
const std::unordered_set<std::string>& get_all_tags() const noexcept
|
||||
{
|
||||
return m_all_tags;
|
||||
}
|
||||
const std::vector<RecruitOperInfo>& get_all_opers() const noexcept
|
||||
{
|
||||
return m_all_opers;
|
||||
}
|
||||
const std::unordered_set<std::string>& get_all_tags() const noexcept { return m_all_tags; }
|
||||
const std::vector<RecruitOperInfo>& get_all_opers() const noexcept { return m_all_opers; }
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
@@ -114,4 +102,4 @@ namespace asst
|
||||
|
||||
std::vector<RecruitOperInfo> m_all_opers;
|
||||
};
|
||||
}
|
||||
} // namespace asst
|
||||
|
||||
@@ -42,9 +42,9 @@ bool asst::RecruitImageAnalyzer::tags_analyze()
|
||||
if (tags_analyzer.analyze()) {
|
||||
m_tags_result = tags_analyzer.get_result();
|
||||
return true;
|
||||
//if (m_tags_result.size() == Resrc.recruit().CorrectNumberOfTags) {
|
||||
// return true;
|
||||
//}
|
||||
// if (m_tags_result.size() == Resrc.recruit().CorrectNumberOfTags) {
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -14,22 +14,10 @@ namespace asst
|
||||
|
||||
virtual bool analyze() override;
|
||||
|
||||
const std::vector<TextRect>& get_tags_result() const noexcept
|
||||
{
|
||||
return m_tags_result;
|
||||
}
|
||||
Rect get_hour_decrement_rect() const noexcept
|
||||
{
|
||||
return m_hour_decrement;
|
||||
}
|
||||
Rect get_minute_decrement_rect() const noexcept
|
||||
{
|
||||
return m_minute_decrement;
|
||||
}
|
||||
Rect get_refresh_rect() const noexcept
|
||||
{
|
||||
return m_refresh_rect;
|
||||
}
|
||||
const std::vector<TextRect>& get_tags_result() const noexcept { return m_tags_result; }
|
||||
Rect get_hour_decrement_rect() const noexcept { return m_hour_decrement; }
|
||||
Rect get_minute_decrement_rect() const noexcept { return m_minute_decrement; }
|
||||
Rect get_refresh_rect() const noexcept { return m_refresh_rect; }
|
||||
|
||||
private:
|
||||
// 该分析器不支持外部设置ROI
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
asst::RecruitTask::RecruitTask(const AsstCallback& callback, void* callback_arg)
|
||||
: PackageTask(callback, callback_arg, TaskType),
|
||||
m_auto_recruit_task_ptr(std::make_shared<AutoRecruitTask>(callback, callback_arg, TaskType))
|
||||
m_auto_recruit_task_ptr(std::make_shared<AutoRecruitTask>(callback, callback_arg, TaskType))
|
||||
{
|
||||
m_subtasks.emplace_back(m_auto_recruit_task_ptr)->set_retry_times(5);
|
||||
}
|
||||
@@ -65,7 +65,8 @@ bool asst::RecruitTask::set_params(const json::value& params)
|
||||
.set_penguin_enabled(penguin_enabled, penguin_id)
|
||||
.set_yituliu_enabled(yituliu_enabled)
|
||||
.set_server(server)
|
||||
.set_set_time(set_time).set_retry_times(3);
|
||||
.set_set_time(set_time)
|
||||
.set_retry_times(3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user