diff --git a/resource/copilot/SSS_约翰老妈新建地块.json b/resource/copilot/SSS_约翰老妈新建地块.json new file mode 100644 index 0000000000..401402033a --- /dev/null +++ b/resource/copilot/SSS_约翰老妈新建地块.json @@ -0,0 +1,470 @@ +{ + "type": "SSS", + "stage_name": "约翰老妈新建地块", + "minimum_required": "v4.9.0", + "doc": { + "title": "约翰老妈保全(应急未测试)", + "title_color": "dark", + "details": "作者:YueShen\n约翰老妈(应急未测试)只能打到第5关,第5关还要看运气\n选战术装备整理箱\n尽量带档二先锋1技能\n要手动编队\n有问题群里找管理咕咕咕", + "details_color": "dark" + }, + "buff": "战术装备整理箱", + "equipment": [ + "A", "A", "A", "A", + "A", "A", "A", "A" + ], + "strategy": "优选策略", + "opers": [ + { + "name": "棘刺", + "skill": 3, + "skill_usage": 1 + }, + { + "name": "泥岩", + "skill": 2, + "skill_usage": 0 + }, + { + "name": "桃金娘", + "skill": 1, + "skill_usage": 1 + }, + { + "name": "煌", + "skill": 2, + "skill_usage": 0 + }, + { + "name": "塞雷娅", + "skill": 1, + "skill_usage": 0 + }, + { + "name": "伊芙利特", + "skill": 2, + "skill_usage": 0 + }, + { + "name": "铃兰", + "skill": 2, + "skill_usage": 0 + } + ], + "tool_men": { + "先锋": 1, + "近卫": 2, + "辅助": 6, + "重装": 2, + "术士": 2 + }, + "drops": [ + "重装", + "近卫", + "无需增调干员", + "术士", + "辅助", + "医疗", + "狙击", + "战备激活阀", + "改派发讯器", + "反制导能组件", + "装备扩充箱" + ], + "blacklist": [ + "罗比菈塔", + "掠风", + "白铁", + "史尔特尔", + "玛恩纳", + "龙舌兰", + "幽灵鲨", + "陈", + "耀骑士临光", + "斯卡蒂", + "赫拉格", + "宴", + "重岳", + "莫斯提马", + "远山", + "天火", + "炎熔", + "赤冬", + "炎狱炎熔", + "莱恩哈特", + "格雷伊", + "蚀清", + "梅尔", + "罗小黑", + "U-Official", + "阿米娅", + "玫兰莎" + ], + "stages": [ + { + "stage_name": "知难而进", + "strategies": [ + { + "core": "煌", + "tool_men": { + "近卫": 1 + }, + "location": [ + 5, + 5 + ], + "direction": "Up" + }, + { + "tool_men": { + "先锋": 100 + }, + "location": [ + 7, + 1 + ], + "direction": "Down" + }, + { + "core": "塞雷娅", + "tool_men": { + "重装": 1 + }, + "location": [ + 5, + 4 + ], + "direction": "Up" + }, + { + "tool_men": { + "辅助": 100 + }, + "location": [ + 6, + 5 + ], + "direction": "Up" + } + ], + "draw_as_possible": true, + "actions": [ + { + "type": "二倍速" + } + ], + "retry_times": 5 + }, + { + "stage_name": "荒地的手段", + "strategies": [ + { + "tool_men": { + "先锋": 100 + }, + "location": [ + 2, + 1 + ], + "direction": "Right" + }, + { + "core": "棘刺", + "tool_men": { + "近卫": 2 + }, + "location": [ + 2, + 2 + ], + "direction": "Down" + }, + { + "core": "泥岩", + "tool_men": { + "重装": 2 + }, + "location": [ + 2, + 4 + ], + "direction": "Right" + }, + { + "tool_men": { + "辅助": 100 + }, + "location": [ + 5, + 3 + ], + "direction": "Left" + } + ], + "draw_as_possible": true, + "actions": [ + { + "type": "二倍速" + }, + { + "type": "部署", + "name": "塞雷娅", + "location": [ + 3, + 1 + ], + "direction": "Right" + } + ], + "retry_times": 5 + }, + { + "stage_name": "麻木前行", + "strategies": [ + { + "tool_men": { + "先锋": 100 + }, + "location": [ + 8, + 1 + ], + "direction": "Down" + }, + { + "core": "棘刺", + "tool_men": { + "近卫": 4 + }, + "location": [ + 7, + 2 + ], + "direction": "Left" + }, + { + "core": "塞雷娅", + "tool_men": { + "重装": 3, + "近卫": 2 + }, + "location": [ + 5, + 2 + ], + "direction": "Left" + }, + { + "core": "伊芙利特", + "tool_men": { + "术士": 2 + }, + "location": [ + 8, + 2 + ], + "direction": "Left" + }, + { + "core": "泥岩", + "tool_men": { + "重装": 1 + }, + "location": [ + 6, + 2 + ], + "direction": "Left" + }, + { + "tool_men": { + "辅助": 100 + }, + "location": [ + 6, + 3 + ], + "direction": "Left" + } + ], + "draw_as_possible": true, + "actions": [ + { + "type": "二倍速" + }, + { + "type": "部署", + "name": "战备激活阀", + "location": [ + 5, + 3 + ], + "direction": "Up" + } + ], + "retry_times": 5 + }, + { + "stage_name": "混乱“派对”", + "strategies": [ + { + "tool_men": { + "先锋": 100 + }, + "location": [ + 3, + 1 + ], + "direction": "Right" + }, + { + "core": "棘刺", + "tool_men": { + "近卫": 3 + }, + "location": [ + 3, + 2 + ], + "direction": "Right" + }, + { + "core": "塞雷娅", + "tool_men": { + "重装": 3 + }, + "location": [ + 4, + 2 + ], + "direction": "Right" + }, + { + "core": "泥岩", + "tool_men": { + "重装": 3 + }, + "location": [ + 4, + 3 + ], + "direction": "Right" + }, + { + "tool_men": { + "辅助": 100, + "术士": 100 + }, + "location": [ + 2, + 2 + ], + "direction": "Right" + } + ], + "draw_as_possible": true, + "actions": [ + { + "type": "二倍速" + }, + { + "type": "部署", + "name": "战备激活阀", + "location": [ + 3, + 3 + ], + "direction": "Up" + } + ], + "retry_times": 5 + }, + { + "stage_name": "消息传递", + "strategies": [ + { + "tool_men": { + "先锋": 100 + }, + "location": [ + 8, + 2 + ], + "direction": "Down" + }, + { + "core": "煌", + "tool_men": { + "近卫": 4 + }, + "location": [ + 7, + 3 + ], + "direction": "Left" + }, + { + "core": "塞雷娅", + "tool_men": { + "重装": 3, + "近卫": 2 + }, + "location": [ + 6, + 3 + ], + "direction": "Left" + }, + { + "tool_men": { + "辅助": 100, + "术士": 100 + }, + "location": [ + 7, + 2 + ], + "direction": "Left" + } + ], + "draw_as_possible": true, + "actions": [ + { + "type": "CheckIfStartOver", + "name": "铃兰" + }, + { + "type": "部署", + "name": "铃兰", + "location": [ + 3, + 4 + ], + "direction": "Right" + }, + { + "type": "二倍速" + }, + { + "type": "部署", + "name": "伊芙利特", + "location": [ + 9, + 3 + ], + "direction": "Left" + }, + { + "type": "部署", + "name": "战备激活阀", + "location": [ + 7, + 4 + ], + "direction": "Up" + } + ], + "retry_times": 5 + } + ] +} diff --git a/resource/tasks.json b/resource/tasks.json index 671e114789..c48f669085 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -5908,7 +5908,12 @@ 800, 100 ], - "ocrReplace": [] + "ocrReplace": [ + [ + ".*前顾后", + "瞻前顾后" + ] + ] }, "BattleSupportUnitFormation": { "action": "ClickSelf", diff --git a/src/MaaCore/Assistant.cpp b/src/MaaCore/Assistant.cpp index 0644b2368e..02469a8bb2 100644 --- a/src/MaaCore/Assistant.cpp +++ b/src/MaaCore/Assistant.cpp @@ -5,7 +5,6 @@ #include #include "Config/GeneralConfig.h" -#include "Config/Miscellaneous/OcrPack.h" #include "Controller/Controller.h" #include "Status.h" #include "Task/Interface/AwardTask.h" @@ -284,7 +283,6 @@ asst::Assistant::AsyncCallId asst::Assistant::async_connect(const std::string& a LogTraceFunction; return append_async_call( - AsyncCallItem::Type::Connect, AsyncCallItem::ConnectParams { .adb_path = adb_path, .address = address, .config = config }, block); } @@ -292,14 +290,14 @@ asst::Assistant::AsyncCallId asst::Assistant::async_click(int x, int y, bool blo { LogTraceFunction; - return append_async_call(AsyncCallItem::Type::Click, AsyncCallItem::ClickParams { .x = x, .y = y }, block); + return append_async_call(AsyncCallItem::ClickParams { .x = x, .y = y }, block); } asst::Assistant::AsyncCallId asst::Assistant::async_screencap(bool block) { LogTraceFunction; - return append_async_call(AsyncCallItem::Type::Screencap, AsyncCallItem::ScreencapParams {}, block); + return append_async_call(AsyncCallItem::ScreencapParams {}, block); } bool asst::Assistant::connected() const @@ -447,17 +445,15 @@ void Assistant::msg_proc() } } -asst::Assistant::AsyncCallId asst::Assistant::append_async_call(AsyncCallItem::Type type, AsyncCallItem::Parmas params, - bool block) +asst::Assistant::AsyncCallId asst::Assistant::append_async_call(AsyncCallItem::Params params, bool block) { LogTraceFunction; - AsyncCallId id = 0; + AsyncCallId id; { std::unique_lock lock(m_call_mutex); id = ++m_call_id; - AsyncCallItem item { .id = id, .type = type, .params = std::move(params) }; - + AsyncCallItem item = { .id = id, .params = std::move(params) }; m_call_queue.emplace(std::move(item)); m_call_condvar.notify_one(); } @@ -473,12 +469,9 @@ asst::Assistant::AsyncCallId asst::Assistant::append_async_call(AsyncCallItem::T bool asst::Assistant::wait_async_id(AsyncCallId id) { while (!m_thread_exit) { - std::unique_lock lock(m_completed_call_mutex); - // 需要保证队列中id一定是有序的 - if (id <= m_completed_call) { - return true; - } - m_completed_call_condvar.wait(lock); + auto old = m_completed_call.load(); + if (old >= id) return true; + m_completed_call.wait(old); } return false; } @@ -488,48 +481,46 @@ void asst::Assistant::call_proc() LogTraceFunction; while (!m_thread_exit) { - std::unique_lock lock(m_call_mutex); - if (m_call_queue.empty()) { - m_call_condvar.wait(lock); - continue; + AsyncCallItem call_item; + + { + std::unique_lock lock(m_call_mutex); + if (m_call_queue.empty()) { + m_call_condvar.wait(lock); + continue; + } + call_item = std::move(m_call_queue.front()); + m_call_queue.pop(); } - auto call_item = std::move(m_call_queue.front()); - m_call_queue.pop(); - lock.unlock(); - auto start = std::chrono::steady_clock::now(); bool ret = false; - std::string what; + std::string what = "Unknown"; - switch (call_item.type) { - case AsyncCallItem::Type::Connect: { - what = "Connect"; - const auto& [adb_path, address, config] = std::get(call_item.params); - ret = ctrl_connect(adb_path, address, config); - } break; - case AsyncCallItem::Type::Click: { - what = "Click"; - const auto& [x, y] = std::get(call_item.params); - ret = ctrl_click(x, y); - } break; - case AsyncCallItem::Type::Screencap: { - what = "Screencap"; - std::ignore = std::get(call_item.params); - ret = ctrl_screencap(); - } break; - default: - what = "Unknown"; - ret = false; - break; - } + std::visit( + [&](auto&& args) -> void { + what = args.what; - { - std::unique_lock completed_call_lock(m_completed_call_mutex); - m_completed_call = call_item.id; - m_completed_call_condvar.notify_all(); - } + using T = std::decay_t; + if constexpr (std::is_same_v) { + const auto& [adb_path, address, config] = args; + ret = ctrl_connect(adb_path, address, config); + } + else if constexpr (std::is_same_v) { + const auto& [x, y] = args; + ret = ctrl_click(x, y); + } + else if constexpr (std::is_same_v) { + ret = ctrl_screencap(); + } + else + static_assert(utils::always_false, "non-exhaustive visitor!"); + }, + call_item.params); + + m_completed_call = call_item.id; + m_completed_call.notify_all(); auto cost = std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count(); diff --git a/src/MaaCore/Assistant.h b/src/MaaCore/Assistant.h index 84686e0352..3abc371dcb 100644 --- a/src/MaaCore/Assistant.h +++ b/src/MaaCore/Assistant.h @@ -104,35 +104,34 @@ namespace asst private: struct AsyncCallItem { - enum class Type - { - Connect, - Click, - Screencap, - }; struct ConnectParams { std::string adb_path; std::string address; std::string config; + static constexpr std::string_view what = "Connect"; }; struct ClickParams { int x = 0; int y = 0; + static constexpr std::string_view what = "Click"; }; struct ScreencapParams - {}; - using Parmas = std::variant; + { + static constexpr std::string_view what = "Screencap"; + }; + using Params = std::variant; AsyncCallId id; - Type type; - Parmas params; + Params params; }; - AsyncCallId append_async_call(AsyncCallItem::Type type, AsyncCallItem::Parmas params, bool block = false); + // submit async call task to queue + AsyncCallId append_async_call(AsyncCallItem::Params params, bool block); bool wait_async_id(AsyncCallId id); private: + // thread executing async call tasks one by one from queue void call_proc(); void working_proc(); void msg_proc(); @@ -169,9 +168,7 @@ namespace asst std::mutex m_call_mutex; std::condition_variable m_call_condvar; - AsyncCallId m_completed_call = 0; // 每个实例有自己独立的执行队列,所以不能静态 - std::mutex m_completed_call_mutex; - std::condition_variable m_completed_call_condvar; + std::atomic m_completed_call = 0; // 每个实例有自己独立的执行队列,所以不能静态 std::thread m_msg_thread; std::thread m_call_thread; diff --git a/src/MaaWpfGui/Helper/ConfigurationHelper.cs b/src/MaaWpfGui/Helper/ConfigurationHelper.cs index 4a0aeed92d..bada132f0a 100644 --- a/src/MaaWpfGui/Helper/ConfigurationHelper.cs +++ b/src/MaaWpfGui/Helper/ConfigurationHelper.cs @@ -27,6 +27,8 @@ namespace MaaWpfGui.Helper private static readonly ILogger _logger = Log.ForContext(); + private static readonly object _lock = new object(); + public delegate void ConfigurationUpdateEventHandler(string key, string oldValue, string newValue); public static event ConfigurationUpdateEventHandler ConfigurationUpdateEvent; @@ -91,9 +93,9 @@ namespace MaaWpfGui.Helper public static bool DeleteValue(string key) { var old = string.Empty; - if (_kvs.ContainsKey(key)) + if (_kvs.TryGetValue(key, out var kv)) { - old = _kvs[key]; + old = kv; } _kvs.Remove(key); @@ -174,7 +176,7 @@ namespace MaaWpfGui.Helper /// Save configuration file /// /// The result of saving process - public static bool Save() + private static bool Save() { if (Released) { @@ -189,7 +191,10 @@ namespace MaaWpfGui.Helper try { - File.WriteAllText(_configurationFile, jsonStr); + lock (_lock) + { + File.WriteAllText(_configurationFile, jsonStr); + } } catch (Exception e) {