This commit is contained in:
ABA2396
2022-06-09 03:07:30 +08:00
28 changed files with 343 additions and 174 deletions

View File

@@ -1,12 +1,11 @@
- 自动战斗
- 修复击杀数识别错误
- 修复偶尔部署不上去的问题
- 版本亮点
- 新增支持开机自启动、启动后自动开机模拟器及游戏、启动后自动 LinkStart, 请进入设置中开启使用~ (模拟器等待时间建议设大点)
- 刷理智
- 新增支持游戏崩溃重连,需要在设置中开启 `唤醒设置`
- 修复一个刷理智时的识别错误
- 修复一个掉落识别错误的
- 修复勾选材料后刷几次就自动停了的问题
- 自动战斗
- 修复不开技能的问题
- 修复尽可能开技能干员一直点不上的问题
- 允许使用鼠标拖拽选择作业文件
- 其他
- 新增 adb 出错后的重连机制;及重连失败时的报错
- 优化了刷理智时游戏崩溃后重连机制
- 其他的一些小问题优化及修复

View File

@@ -69,6 +69,10 @@
"$ref": "#/definitions/TaskNameList",
"description": "可选项,表示达到了最大执行次数后要执行的任务\n不填写时达到了最大执行次数则停止填写后就执行这里的而不是 next 里的"
},
"onErrorNext": {
"$ref": "#/definitions/TaskNameList",
"description": "可选项,表示执行出错时,后续要执行的任务"
},
"preDelay": {
"type": "number",
"description": "可选项,表示识别到后延迟多久才执行 action单位毫秒不填写时默认 0"
@@ -218,4 +222,4 @@
]
}
}
}
}

View File

@@ -53,6 +53,8 @@
"exceededNext": [ "OtherTaskName1", "OtherTaskName2" ],
// 可选项,表示达到了最大执行次数后要执行的任务
// 不填写时,达到了最大执行次数则停止;填写后就执行这里的,而不是 next 里的
"onErrorNext": [ "OtherTaskName1", "OtherTaskName2" ],
// 可选项,表示执行出错时,后续要执行的任务
"preDelay": 1000, // 可选项,表示识别到后延迟多久才执行 action单位毫秒不填写时默认 0
"rearDelay": 1000, // 可选项,表示 action 执行完后延迟多久才去识别 next, 单位毫秒;不填写时默认 0

View File

@@ -200,6 +200,8 @@ Todo
肉鸽关卡:紧急作战
- `Roguelike1StageDreadfulFoe`
肉鸽关卡:险路恶敌
- `StartGameTask`
打开客户端失败配置文件与传入client_type不匹配
- Todo 其他
#### SubTaskExtraInfo
@@ -290,6 +292,16 @@ Todo
}
```
- `RecruitRobotTag`
公招识别到了小车 Tag 且跳过小车(即用户需要小车)
```jsonc
// 对应的 details 字段举例
{
"tag": "支援机械"
}
```
- `RecruitResult`
公招识别结果
@@ -356,7 +368,8 @@ Todo
}
]
}
]
],
"robot": True // 公招识别到了小车 Tag 且跳过小车(即用户需要小车)
}
```

View File

@@ -33,7 +33,15 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p
- `StartUp`
开始唤醒
不支持设置参数
```jsonc
// 对应的任务参数
{
"client_type": string, // 客户端版本,可选,默认为空
// 选项:"Official" | "Bilibili"
"start_game_enable": bool // 是否自动启动客户端,可选,默认不启动
}
```
- `Fight`
刷理智
@@ -78,6 +86,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p
"expedite": bool, // 是否使用加急许可,可选,默认 false
"expedite_times": int, // 加急次数,仅在 expedite 为 true 时有效。
// 可选,默认无限使用(直到 times 达到上限)
"skip_robot": bool // 是否在识别到小车词条时跳过,可选,默认跳过
}
```
@@ -94,7 +103,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p
"drones": string, // 无人机用途,可选项,默认 _NotUse
// "_NotUse"、"Money"、"SyntheticJade"、"CombatRecord"、"PureGold"、"OriginStone"、"Chip"
"threshold": float, // 宿舍进驻心情阈值,可选,取值范围 [0, 1.0],默认 0.3
"replenish": bool, // 贸易站“源石碎片”是否自动补货,可选,默认 false
"replenish": bool // 贸易站“源石碎片”是否自动补货,可选,默认 false
}
```
@@ -112,6 +121,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p
"shopping": bool, // 是否购物,可选,默认 false。不支持运行中设置
"buy_first": [ // 优先购买列表,可选。不支持运行中设置
string, // 商品名,如 "招聘许可"、"龙门币" 等
...
],
"blacklist": [ // 黑名单列表,可选。不支持运行中设置
string, // 商品名,如 "加急许可"、"家具零件" 等
@@ -129,7 +139,7 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p
```jsonc
{
"mode": int, // 模式,可选项。默认 0
"mode": int // 模式,可选项。默认 0
// 0 - 尽可能一直往后打
// 1 - 第一层投资完源石锭就退出
// 2 - 投资过后再退出,没有投资就继续往后打

View File

@@ -779,6 +779,7 @@
"TodaysSupplies",
"ReturnToTerminal",
"OfflineConfirm",
"EndOfAction",
"StageSNFlag"
]
},
@@ -1263,6 +1264,10 @@
"UseMedicine",
"UseStone",
"NoStone",
"StartToWakeUp",
"StartUpConnectingFlag",
"StartLoginBServer",
"OfflineConfirm",
"ClickCornerAfterPRTS_2"
]
},
@@ -1277,28 +1282,6 @@
10
],
"rearDelay": 3000,
"next": [
"EndOfAction",
"StartButton1",
"StartButton2",
"UseMedicine",
"UseStone",
"NoStone",
"MaybeCrashAndRestartGame"
]
},
"MaybeCrashAndRestartGame": {
"ClickCorner_Doc": "一般能点这么多下还不行的,多半是游戏崩了,所以重启游戏试试",
"Doc": "本任务注册了插件 GameCrashRestartTaskPlugin",
"algorithm": "JustReturn",
"action": "ClickRect",
"specificRect": [
1000,
120,
270,
10
],
"rearDelay": 3000,
"next": [
"EndOfAction",
"StartButton1",
@@ -1310,12 +1293,10 @@
"StartToWakeUp",
"StartUpConnectingFlag",
"StartLoginBServer",
"Terminal",
"CloseAnno",
"TodaysSupplies",
"ReturnToTerminal",
"OfflineConfirm",
"StageSNFlag"
"OfflineConfirm"
],
"onErrorNext": [
"RestartGameAndContinueFighting"
]
},
"EndOfAction": {
@@ -1352,6 +1333,24 @@
"UseStone",
"NoStone",
"EndOfAction"
],
"onErrorNext": [
"RestartGameAndContinueFighting"
]
},
"RestartGameAndContinueFighting": {
"algorithm": "JustReturn",
"action": "DoNothing",
"rearDelay": 5000,
"next": [
"GameStart",
"StartToWakeUp",
"StartUpConnectingFlag",
"StartLoginBServer",
"Terminal",
"CloseAnno",
"TodaysSupplies",
"OfflineConfirm"
]
},
"UseMedicine": {
@@ -1500,6 +1499,9 @@
"StartLoginBServer",
"OfflineConfirm",
"StartButton1"
],
"onErrorNext": [
"ClickCornerAfterPRTS_1"
]
},
"OfflineConfirmAfterBattle": {

View File

@@ -322,5 +322,6 @@ void asst::Assistant::append_callback(AsstMsg msg, json::value detail)
void Assistant::clear_cache()
{
m_status->clear_number();
//Task.clear_cache();
m_status->clear_rect();
m_status->clear_str();
}

View File

@@ -98,7 +98,7 @@ namespace asst
}
Rect move(Rect move) const
{
return {x + move.x, y + move.y, move.width, move.height};
return { x + move.x, y + move.y, move.width, move.height };
}
int x = 0;
@@ -158,7 +158,6 @@ namespace asst
double score = 0.0;
Rect rect;
};
}
namespace std
@@ -225,6 +224,7 @@ namespace asst
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
asst::Rect specific_rect; // 指定区域目前仅针对ClickRect任务有用会点这个区域
int pre_delay = 0; // 执行该任务前的延时

View File

@@ -518,7 +518,7 @@ bool asst::BattleProcessTask::oper_retreat(const BattleAction& action)
action.location.x == 0 && action.location.y == 0 &&
iter != m_used_opers.cend()) {
pos = iter->second.pos;
m_used_opers.erase(name);
m_used_opers.erase(iter);
}
else {
pos = m_normal_tile_info.at(action.location).pos;
@@ -537,7 +537,6 @@ bool asst::BattleProcessTask::use_skill(const BattleAction& action)
action.location.x == 0 && action.location.y == 0 &&
iter != m_used_opers.cend()) {
pos = iter->second.pos;
m_used_opers.erase(name);
}
else {
pos = m_normal_tile_info.at(action.location).pos;
@@ -571,6 +570,7 @@ bool asst::BattleProcessTask::try_possible_skill(const cv::Mat& image)
continue;
}
m_ctrler->click(info.pos);
sleep(Task.get("BattleUseOper")->pre_delay);
used |= ProcessTask(*this, { "BattleSkillReadyOnClick" }).set_task_delay(0).run();
if (info.info.skill_usage == BattleSkillUsage::Once) {
info.info.skill_usage = BattleSkillUsage::OnceUsed;

View File

@@ -480,11 +480,11 @@ void asst::Controller::clear_info() noexcept
m_height = 0;
m_control_scale = 1.0;
m_scale_size = { WindowWidthDefault, WindowHeightDefault };
m_server_started = false;
if (m_support_socket && m_server_started && m_server_sock) {
if (m_server_sock) {
::closesocket(m_server_sock);
m_server_sock = 0U;
}
m_server_started = false;
--m_instance_count;
}

View File

@@ -37,7 +37,9 @@ asst::FightTask::FightTask(AsstCallback callback, void* callback_arg)
.set_times_limit("MedicineConfirm", 0)
.set_times_limit("StoneConfirm", 0)
.set_times_limit("StartButton1", INT_MAX)
.set_times_limit("StartButton2", INT_MAX);
.set_times_limit("StartButton2", INT_MAX)
.set_ignore_error(false);
m_stage_drops_plugin_ptr = m_fight_task_ptr->regiseter_plugin<StageDropsTaskPlugin>();
m_stage_drops_plugin_ptr->set_retry_times(0);
m_game_restart_plugin_ptr = m_fight_task_ptr->regiseter_plugin<GameCrashRestartTaskPlugin>();

View File

@@ -1,13 +1,16 @@
#include "GameCrashRestartTaskPlugin.h"
#include "RuntimeStatus.h"
bool asst::GameCrashRestartTaskPlugin::verify(AsstMsg msg, const json::value& details) const
{
if (msg != AsstMsg::SubTaskCompleted
if (msg != AsstMsg::SubTaskStart
|| details.get("subtask", std::string()) != "ProcessTask") {
return false;
}
if (details.at("details").at("task").as_string() == "MaybeCrashAndRestartGame") {
if (details.at("details").at("task").as_string() == "RestartGameAndContinueFighting"
&& m_status->get_number("LastStartButton2")) {
return true;
}
else {

View File

@@ -49,13 +49,9 @@ bool asst::ProcessTask::run()
return false;
}
sleep(m_task_delay);
if (!on_run_fails()) {
return false;
}
}
callback(AsstMsg::SubTaskError, basic_info());
return false;
return on_run_fails();
}
ProcessTask& asst::ProcessTask::set_task_delay(int delay) noexcept
@@ -66,6 +62,7 @@ ProcessTask& asst::ProcessTask::set_task_delay(int delay) noexcept
asst::ProcessTask& asst::ProcessTask::set_tasks(std::vector<std::string> tasks_name) noexcept
{
m_cur_retry = 0;
m_raw_tasks_name = std::move(tasks_name);
return *this;
}
@@ -99,7 +96,6 @@ bool ProcessTask::_run()
Log.info(info.to_string());
Rect rect;
std::shared_ptr<TaskInfo> cur_task_ptr = nullptr;
auto front_task_ptr = Task.get(m_cur_tasks_name.front());
// 可能有配置错误,导致不存在对应的任务
@@ -109,7 +105,7 @@ bool ProcessTask::_run()
}
// 如果第一个任务是JustReturn的那就没必要再截图并计算了
if (front_task_ptr->algorithm == AlgorithmType::JustReturn) {
cur_task_ptr = front_task_ptr;
m_cur_task_ptr = front_task_ptr;
}
else {
const auto image = m_ctrler->get_image();
@@ -120,15 +116,15 @@ bool ProcessTask::_run()
if (!analyzer.analyze()) {
return false;
}
cur_task_ptr = analyzer.get_result();
m_cur_task_ptr = analyzer.get_result();
rect = analyzer.get_rect();
}
if (need_exit()) {
return false;
}
std::string cur_name = cur_task_ptr->name;
std::string cur_name = m_cur_task_ptr->name;
const auto& res_move = cur_task_ptr->rect_move;
const auto& res_move = m_cur_task_ptr->rect_move;
if (!res_move.empty()) {
rect.x += res_move.x;
rect.y += res_move.y;
@@ -138,7 +134,7 @@ bool ProcessTask::_run()
int& exec_times = m_exec_times[cur_name];
int max_times = cur_task_ptr->max_times;
int max_times = m_cur_task_ptr->max_times;
if (auto iter = m_times_limit.find(cur_name);
iter != m_times_limit.cend()) {
max_times = iter->second;
@@ -151,7 +147,7 @@ bool ProcessTask::_run()
{ "max_times", max_times }
};
Log.info("exec times exceeded the limit", info.to_string());
m_cur_tasks_name = cur_task_ptr->exceeded_next;
m_cur_tasks_name = m_cur_task_ptr->exceeded_next;
sleep(m_task_delay);
continue;
}
@@ -161,23 +157,23 @@ bool ProcessTask::_run()
info["details"] = json::object{
{ "task", cur_name },
{ "action", static_cast<int>(cur_task_ptr->action) },
{ "action", static_cast<int>(m_cur_task_ptr->action) },
{ "exec_times", exec_times },
{ "max_times", max_times },
{ "algorithm", static_cast<int>(cur_task_ptr->algorithm) }
{ "algorithm", static_cast<int>(m_cur_task_ptr->algorithm) }
};
callback(AsstMsg::SubTaskStart, info);
// 前置固定延时
if (!sleep(cur_task_ptr->pre_delay)) {
if (!sleep(m_cur_task_ptr->pre_delay)) {
return false;
}
bool need_stop = false;
switch (cur_task_ptr->action) {
switch (m_cur_task_ptr->action) {
case ProcessTaskAction::ClickRect:
rect = cur_task_ptr->specific_rect;
rect = m_cur_task_ptr->specific_rect;
[[fallthrough]];
case ProcessTaskAction::ClickSelf:
exec_click_task(rect);
@@ -189,11 +185,11 @@ bool ProcessTask::_run()
} break;
case ProcessTaskAction::SwipeToTheLeft:
case ProcessTaskAction::SwipeToTheRight:
exec_swipe_task(cur_task_ptr->action);
exec_swipe_task(m_cur_task_ptr->action);
break;
case ProcessTaskAction::SlowlySwipeToTheLeft:
case ProcessTaskAction::SlowlySwipeToTheRight:
exec_slowly_swipe_task(cur_task_ptr->action);
exec_slowly_swipe_task(m_cur_task_ptr->action);
break;
case ProcessTaskAction::DoNothing:
break;
@@ -210,7 +206,7 @@ bool ProcessTask::_run()
// 减少其他任务的执行次数
// 例如,进入吃理智药的界面了,相当于上一次点蓝色开始行动没生效
// 所以要给蓝色开始行动的次数减一
for (const std::string& reduce : cur_task_ptr->reduce_other_times) {
for (const std::string& reduce : m_cur_task_ptr->reduce_other_times) {
auto& v = m_exec_times[reduce];
if (v > 0) {
--v;
@@ -218,7 +214,7 @@ bool ProcessTask::_run()
}
// 后置固定延时
int rear_delay = cur_task_ptr->rear_delay;
int rear_delay = m_cur_task_ptr->rear_delay;
if (auto iter = m_rear_delay.find(cur_name);
iter != m_rear_delay.cend()) {
rear_delay = iter->second;
@@ -227,10 +223,10 @@ bool ProcessTask::_run()
return false;
}
for (const std::string& sub : cur_task_ptr->sub) {
for (const std::string& sub : m_cur_task_ptr->sub) {
LogTraceScope("Sub: " + sub);
bool sub_ret = ProcessTask(*this, { sub }).run();
if (!sub_ret && !cur_task_ptr->sub_error_ignored) {
if (!sub_ret && !m_cur_task_ptr->sub_error_ignored) {
Log.error("Sub error and not ignored", sub);
return false;
}
@@ -238,20 +234,32 @@ bool ProcessTask::_run()
callback(AsstMsg::SubTaskCompleted, info);
if (cur_task_ptr->next.empty()) {
if (m_cur_task_ptr->next.empty()) {
need_stop = true;
}
if (need_stop) {
return true;
}
m_cur_tasks_name = cur_task_ptr->next;
m_cur_tasks_name = m_cur_task_ptr->next;
sleep(m_task_delay);
}
return true;
}
bool asst::ProcessTask::on_run_fails()
{
LogTraceFunction;
if (!m_cur_task_ptr || m_cur_task_ptr->on_error_next.empty()) {
return false;
}
set_tasks(m_cur_task_ptr->on_error_next);
return run();
}
void ProcessTask::exec_click_task(const Rect& matched_rect)
{
m_ctrler->click(matched_rect);

View File

@@ -24,11 +24,13 @@ namespace asst
protected:
virtual bool _run() override;
virtual bool on_run_fails() override;
void exec_click_task(const Rect& matched_rect);
void exec_swipe_task(ProcessTaskAction action);
void exec_slowly_swipe_task(ProcessTaskAction action);
std::shared_ptr<TaskInfo> m_cur_task_ptr = nullptr;
std::vector<std::string> m_raw_tasks_name;
std::vector<std::string> m_cur_tasks_name;
std::unordered_map<std::string, int> m_rear_delay;

View File

@@ -11,7 +11,8 @@ asst::StartUpTask::StartUpTask(AsstCallback callback, void* callback_arg)
{
m_start_up_task_ptr->set_tasks({ "StartUp" })
.set_times_limit("ReturnToTerminal", 0)
.set_times_limit("Terminal", 0);
.set_times_limit("Terminal", 0)
.set_times_limit("EndOfAction", 0);
m_subtasks.emplace_back(m_start_game_task_ptr);
m_subtasks.emplace_back(m_start_up_task_ptr);
}

View File

@@ -160,8 +160,11 @@ bool asst::TaskData::parse(const json::value& json)
task_info_ptr->exceeded_next.emplace_back(excceed_next.as_string());
}
}
else {
task_info_ptr->exceeded_next.emplace_back("Stop");
if (task_json.contains("onErrorNext")) {
const json::array& on_error_next_arr = task_json.at("onErrorNext").as_array();
for (const json::value& on_error_next : on_error_next_arr) {
task_info_ptr->on_error_next.emplace_back(on_error_next.as_string());
}
}
task_info_ptr->pre_delay = task_json.get("preDelay", 0);
task_info_ptr->rear_delay = task_json.get("rearDelay", 0);

View File

@@ -12,6 +12,7 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -86,8 +87,21 @@ namespace MeoAsstGui
Environment.Exit(0);
});
}
var tvm = _container.Get<TaskQueueViewModel>();
tvm.Idle = true;
var mainModel = _container.Get<TaskQueueViewModel>();
mainModel.Idle = true;
var settingsModel = _container.Get<SettingsViewModel>();
Execute.OnUIThread(() =>
{
Task.Run(() =>
{
settingsModel.TryToStartEmulator();
});
if (settingsModel.RunDirectly)
{
mainModel.LinkStart();
}
});
}
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
@@ -383,7 +397,7 @@ namespace MeoAsstGui
mainModel.AddLog("投资达到上限", "darkcyan");
break;
case "MaybeCrashAndRestartGame":
case "RestartGameAndContinueFighting":
mainModel.AddLog("游戏崩溃,重新启动", "darkgoldenrod");
break;
@@ -604,16 +618,6 @@ namespace MeoAsstGui
}
break;
case "RecruitSpecialTag":
{
string special = subTaskDetails["tag"].ToString();
using (var toast = new ToastNotification("公招提示"))
{
toast.AppendContentText(special).ShowRecruit();
}
}
break;
case "RecruitResult":
{
string resultContent = string.Empty;
@@ -635,13 +639,6 @@ namespace MeoAsstGui
resultContent += "\n\n";
}
recruitModel.RecruitResult = resultContent;
if (level >= 5)
{
using (var toast = new ToastNotification($"公招出 {level} 星了哦!"))
{
toast.AppendContentText(new string('★', level)).ShowRecruit(row: 2);
}
}
}
break;
}

View File

@@ -138,7 +138,7 @@
<Compile Include="UserControl\VersionUpdateSettingsUserControl.xaml.cs">
<DependentUpon>VersionUpdateSettingsUserControl.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\StartAppModel.cs" />
<Compile Include="ViewModels\StartSelfModel.cs" />
<Compile Include="ViewModels\RecruitViewModel.cs" />
<Compile Include="ViewModels\RootViewModel.cs" />
<Compile Include="ViewModels\CopilotViewModel.cs" />

View File

@@ -8,31 +8,39 @@
mc:Ignorable="d"
xmlns:vm="clr-namespace:MeoAsstGui;assembly=MeoAsstGui"
d:DataContext="{d:DesignInstance {x:Type vm:SettingsViewModel}}"
d:DesignHeight="90" d:DesignWidth="400">
d:DesignHeight="300" d:DesignWidth="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<CheckBox IsChecked="{Binding StartAppEnable}" Block.TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Center"
Content="开机自启" Height="25" Width="74"/>
<CheckBox Grid.Row="1" IsChecked="{Binding StartGameEnable}" Block.TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Center"
Content="启动游戏" Height="25" Width="74"/>
<TextBlock Grid.Row="0" Grid.Column="1" Style="{StaticResource TextBlockDefault}" Block.TextAlignment="Center" Text="游戏服务器"/>
<ComboBox Grid.Row="1"
Grid.Column="1"
IsEnabled="{Binding StartGameEnable}"
IsHitTestVisible ="{Binding Idle}"
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<CheckBox IsChecked="{Binding StartSelf}" Block.TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10"
Content="开机自动启动 " />
<CheckBox IsChecked="{Binding RunDirectly}" Block.TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10"
Content="启动后直接运行 " />
<CheckBox IsChecked="{Binding StartEmulator}" Block.TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10"
Content="启动后自动开启模拟器" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10">
<TextBlock Margin="3" Style="{StaticResource TextBlockDefault}" Block.TextAlignment="Center" Text="等待模拟器&#xA;启动时间(秒)" />
<TextBox Margin="3" Text="{Binding EmulatorWaitSeconds}" IsEnabled="{Binding StartEmulator}" InputMethod.IsInputMethodEnabled="False" Width="50" />
</StackPanel>
</StackPanel>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Margin="10" Style="{StaticResource TextBlockDefault}" Block.TextAlignment="Center" Text="模拟器路径" />
<Button Command="{s:Action SelectEmulatorExec}" Content="选择" Margin="10" />
</StackPanel>
<TextBox Text="{Binding EmulatorPath}" Margin="10" />
<TextBlock Margin="10" Style="{StaticResource TextBlockDefault}" Block.TextAlignment="Center" Text="客户端版本" />
<ComboBox IsHitTestVisible ="{Binding Idle}" Margin="10"
ItemsSource="{Binding ClientTypeList}"
DisplayMemberPath="Display"
SelectedValuePath="Value"
SelectedValue="{Binding ClientType}" Width="100"/>
SelectedValue="{Binding ClientType}" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -16,21 +16,20 @@
</Grid.ColumnDefinitions>
<StackPanel>
<CheckBox
<CheckBox
Content="使用Windows系统推送通知Win10/Win11"
HorizontalAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsChecked="{Binding ToastUsingSystem}"
IsChecked="{Binding ToastUsingSystem}"
Visibility="{c:Binding ToastOS, FalseToVisibility=Collapsed}"
/>
Margin="10" />
<TextBlock
HorizontalAlignment="Center" Block.TextAlignment="Center"
Style="{StaticResource TextBlockDefault}"
TextWrapping="Wrap"
Text="默认通知显示位置设置,系统通知无效,若无勾选则只有通知提示音"
Margin="0,10,0,0"
/>
<Border BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" CornerRadius="4" MaxWidth="400">
Margin="10" />
<Border BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" CornerRadius="4" MaxWidth="400" Margin="10">
<Grid IsEnabled="{c:Binding !(ToastOS and ToastUsingSystem)}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
@@ -45,35 +44,35 @@
<CheckBox
Grid.Row="0" Grid.Column="0" Margin="16" HorizontalAlignment="Left"
VerticalAlignment="Top" Content="↖ 左上"
IsChecked="{Binding ToastPositionTopLeft}"/>
IsChecked="{Binding ToastPositionTopLeft}" />
<CheckBox
Grid.Row="1" Grid.Column="0" Margin="16" HorizontalAlignment="Left"
VerticalAlignment="Center" Content="← 左边"
IsChecked="{Binding ToastPositionCenterLeft}"/>
IsChecked="{Binding ToastPositionCenterLeft}" />
<CheckBox
Grid.Row="2" Grid.Column="0" Margin="16" HorizontalAlignment="Left"
VerticalAlignment="Bottom" Content="↙ 左下"
IsChecked="{Binding ToastPositionBottomLeft}"/>
IsChecked="{Binding ToastPositionBottomLeft}" />
<CheckBox
Grid.Row="0" Grid.Column="1" Margin="16" HorizontalAlignment="Center"
VerticalAlignment="Top" Content="↑ 上边"
IsChecked="{Binding ToastPositionTopCenter}"/>
IsChecked="{Binding ToastPositionTopCenter}" />
<CheckBox
Grid.Row="2" Grid.Column="1" Margin="16" HorizontalAlignment="Center"
VerticalAlignment="Bottom" Content="↓ 下边"
IsChecked="{Binding ToastPositionBottomCenter}"/>
IsChecked="{Binding ToastPositionBottomCenter}" />
<CheckBox
Grid.Row="0" Grid.Column="2" Margin="16" HorizontalAlignment="Right"
VerticalAlignment="Top" Content="↗ 右上"
IsChecked="{Binding ToastPositionTopRight}"/>
IsChecked="{Binding ToastPositionTopRight}" />
<CheckBox
Grid.Row="1" Grid.Column="2" Margin="16" HorizontalAlignment="Right"
VerticalAlignment="Center" Content="→ 右边"
IsChecked="{Binding ToastPositionCenterRight}"/>
IsChecked="{Binding ToastPositionCenterRight}" />
<CheckBox
Grid.Row="2" Grid.Column="2" Margin="16" HorizontalAlignment="Right"
VerticalAlignment="Bottom" Content="↘ 右下"
IsChecked="{Binding ToastPositionBottomRight}"/>
IsChecked="{Binding ToastPositionBottomRight}" />
</Grid>
</Border>
</StackPanel>

View File

@@ -16,7 +16,7 @@
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="3">
<CheckBox IsChecked="{Binding UpdateCheck}" IsEnabled="False" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Margin="10" Content="检查更新" />
<CheckBox IsChecked="{Binding UpdateCheck}" IsEnabled="False" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Margin="10" Content="自动检查更新" />
<CheckBox IsChecked="{Binding AutoDownloadUpdatePackage}" IsEnabled="{Binding UpdateCheck}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Margin="10" Content="自动下载更新包" />
<CheckBox IsChecked="{Binding UpdateBeta}" IsEnabled="{Binding UpdateCheck}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Margin="10" Content="检查测试版本更新" />
<CheckBox IsChecked="{Binding UseAria2}" IsEnabled="{Binding UpdateCheck}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Margin="10" Content="使用 aria2 进行下载" />
@@ -27,11 +27,13 @@
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Style="{StaticResource TextBlockDefault}" VerticalAlignment="Center" Text="Http Proxy" Margin="1" />
<TextBox Grid.Row="1" Text="{Binding Proxy}" Margin="10" Width="150" VerticalAlignment="Center" InputMethod.IsInputMethodEnabled="False" />
<TextBlock Grid.Row="2" Style="{StaticResource TextBlockDefault}" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding VersionInfo, Mode=OneWay}" Margin="10" />
<Button Grid.Row="3" Command="{s:Action ManualUpdate}" Content="检查更新" Margin="10" />
</Grid>
</StackPanel>
</Grid>

View File

@@ -18,12 +18,15 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Notification.Wpf.Constants;
using Notification.Wpf.Controls;
using Stylet;
using StyletIoC;
using DragEventArgs = System.Windows.DragEventArgs;
using Screen = Stylet.Screen;
namespace MeoAsstGui
{
@@ -182,6 +185,29 @@ namespace MeoAsstGui
}
}
public void DropFile(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(DataFormats.FileDrop))
{
return;
}
var filename = ((Array)e.Data.GetData(DataFormats.FileDrop))?.GetValue(0).ToString();
if (filename == null)
{
return;
}
if (filename.EndsWith(".json"))
{
Filename = filename;
}
else
{
Filename = "";
ClearLog();
AddLog("此文件非json文件","darkred");
}
}
private bool _form = false;
public bool Form

View File

@@ -16,6 +16,8 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Notification.Wpf.Constants;
using Notification.Wpf.Controls;
using Stylet;
@@ -47,14 +49,13 @@ namespace MeoAsstGui
_listTitle.Add("肉鸽设置");
_listTitle.Add("自动公招");
_listTitle.Add("信用商店");
_listTitle.Add("定时执行");
_listTitle.Add("启动设置");
_listTitle.Add("企鹅数据");
_listTitle.Add("连接设置");
_listTitle.Add("启动设置");
_listTitle.Add("定时执行");
_listTitle.Add("通知显示");
_listTitle.Add("软件更新");
_listTitle.Add("关于我们");
//_listTitle.Add("其他");
InfrastInit();
ToastPositionInit();
@@ -136,6 +137,7 @@ namespace MeoAsstGui
ClientTypeList = new List<CombData>
{
new CombData { Display = "不选择", Value = "" },
new CombData { Display = "官服", Value = "Official" },
new CombData { Display = "Bilibili服", Value = "Bilibili" }
};
@@ -153,31 +155,96 @@ namespace MeoAsstGui
}
/* 启动设置 */
private bool _startAppEnable = StartAppModel.CheckStart();
public bool StartAppEnable
private bool _startSelf = StartSelfModel.CheckStart();
public bool StartSelf
{
get { return _startAppEnable; }
get { return _startSelf; }
set
{
SetAndNotify(ref _startAppEnable, value);
StartAppModel.SetStart(value);
SetAndNotify(ref _startSelf, value);
StartSelfModel.SetStart(value);
}
}
private bool _startGameEnable = Convert.ToBoolean(ViewStatusStorage.Get("Start.StartGameEnable", bool.FalseString));
private bool _runDirectly = Convert.ToBoolean(ViewStatusStorage.Get("Start.RunDirectly", bool.FalseString));
public bool StartGameEnable
public bool RunDirectly
{
get { return _startGameEnable; }
get { return _runDirectly; }
set
{
SetAndNotify(ref _startGameEnable, value);
ViewStatusStorage.Set("Start.StartGameEnable", value.ToString());
SetAndNotify(ref _runDirectly, value);
ViewStatusStorage.Set("Start.RunDirectly", value.ToString());
}
}
private string _clientType = ViewStatusStorage.Get("Start.ClientType", "Official");
private bool _startEmulator = Convert.ToBoolean(ViewStatusStorage.Get("Start.StartEmulator", bool.FalseString));
public bool StartEmulator
{
get { return _startEmulator; }
set
{
SetAndNotify(ref _startEmulator, value);
ViewStatusStorage.Set("Start.StartEmulator", value.ToString());
}
}
private string _emulatorPath = ViewStatusStorage.Get("Start.EmulatorPath", string.Empty);
public string EmulatorPath
{
get { return _emulatorPath; }
set
{
SetAndNotify(ref _emulatorPath, value);
ViewStatusStorage.Set("Start.EmulatorPath", value);
}
}
private string _emulatorWaitSeconds = ViewStatusStorage.Get("Start.EmulatorWaitSeconds", "60");
public string EmulatorWaitSeconds
{
get { return _emulatorWaitSeconds; }
set
{
SetAndNotify(ref _emulatorWaitSeconds, value);
ViewStatusStorage.Set("Start.EmulatorWaitSeconds", value);
}
}
public void TryToStartEmulator()
{
if (!StartEmulator
|| EmulatorPath.Length == 0
|| !File.Exists(EmulatorPath))
{
return;
}
System.Diagnostics.Process.Start(EmulatorPath);
int delay = 0;
if (!int.TryParse(EmulatorWaitSeconds, out delay))
{
delay = 60;
}
Thread.Sleep(delay * 1000);
}
public void SelectEmulatorExec()
{
var dialog = new Microsoft.Win32.OpenFileDialog();
dialog.Filter = "模拟器程序|*.exe";
if (dialog.ShowDialog() == true)
{
EmulatorPath = dialog.FileName;
}
}
private string _clientType = ViewStatusStorage.Get("Start.ClientType", "");
public string ClientType
{
@@ -983,7 +1050,22 @@ namespace MeoAsstGui
}
}
/* 调试设置 */
public void ManualUpdate()
{
var updateModle = _container.Get<VersionUpdateViewModel>();
Task.Run(() =>
{
if (!updateModle.CheckAndDownloadUpdate(true))
{
using (var toast = new ToastNotification("已是最新版本~"))
{
toast.Show();
}
}
});
}
/* 连接设置 */
private string _connectAddress = ViewStatusStorage.Get("Connect.Address", string.Empty);
@@ -1116,21 +1198,21 @@ namespace MeoAsstGui
rvm.WindowTitle = string.Format("MaaAssistantArknights - {0} ({1})", ConnectConfigName, ConnectAddress);
}
private string bluestacksConfig = ViewStatusStorage.Get("Bluestacks.Config.Path", string.Empty);
private string _bluestacksConfig = ViewStatusStorage.Get("Bluestacks.Config.Path", string.Empty);
public void TryToSetBlueStacksHyperVAddress()
{
if (bluestacksConfig.Length == 0)
if (_bluestacksConfig.Length == 0)
{
return;
}
if (!File.Exists(bluestacksConfig))
if (!File.Exists(_bluestacksConfig))
{
ViewStatusStorage.Set("Bluestacks.Config.Error", "File not exists");
return;
}
var all_lines = File.ReadAllLines(bluestacksConfig);
var all_lines = File.ReadAllLines(_bluestacksConfig);
foreach (var line in all_lines)
{
if (line.StartsWith("bst.instance.Nougat64.status.adb_port"))

View File

@@ -14,16 +14,18 @@ using Microsoft.Win32;
namespace MeoAsstGui
{
public class StartAppModel
public class StartSelfModel
{
private static RegistryKey _key = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true);
private static string fileValue = Process.GetCurrentProcess().MainModule.FileName;
public static bool CheckStart()
{
if (_key.GetValue("MeoAsst") == null)
return false;
else return true;
}
public static bool SetStart(bool set)
{
if (set)
@@ -36,7 +38,6 @@ namespace MeoAsstGui
_key.DeleteValue("MeoAsst");
return !CheckStart();
}
}
}
}

View File

@@ -346,7 +346,7 @@ namespace MeoAsstGui
var settings = _container.Get<SettingsViewModel>();
var asstProxy = _container.Get<AsstProxy>();
var mode = settings.ClientType;
var enable = settings.StartGameEnable;
var enable = mode.Length != 0;
return asstProxy.AsstAppendStartUp(mode, enable);
}

View File

@@ -77,6 +77,7 @@ namespace MeoAsstGui
}
private string _updateUrl;
public string UpdateUrl
{
get
@@ -88,6 +89,7 @@ namespace MeoAsstGui
SetAndNotify(ref _updateUrl, value);
}
}
public FlowDocument UpdateInfoDocument
{
get
@@ -233,10 +235,10 @@ namespace MeoAsstGui
/// </summary>
/// <returns>操作成功返回 true反之则返回 false</returns>
public bool CheckAndDownloadUpdate()
public bool CheckAndDownloadUpdate(bool force = false)
{
// 检查更新
if (!CheckUpdate())
if (!CheckUpdate(force))
{
return false;
}
@@ -338,10 +340,10 @@ namespace MeoAsstGui
/// </summary>
/// <returns>操作成功返回 true反之则返回 false</returns>
public bool CheckUpdate()
public bool CheckUpdate(bool force = false)
{
//开发版不检查更新
if (!isStableVersion())
if (!force && !isStableVersion())
{
return false;
}

View File

@@ -9,7 +9,9 @@
mc:Ignorable="d"
xmlns:vm="clr-namespace:MeoAsstGui;assembly=MeoAsstGui"
d:DataContext="{d:DesignInstance {x:Type vm:CopilotViewModel}}"
d:DesignHeight="495" d:DesignWidth="800">
d:DesignHeight="495" d:DesignWidth="800"
AllowDrop="True"
Drop="{s:Action DropFile}">
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition />

View File

@@ -38,22 +38,22 @@
<local:MallSettingsUserControl IsEnabled="{Binding Idle}" Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[4]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:TimerSettingsUserControl IsEnabled="{Binding Idle}" Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[5]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:StartSettingsUserControl IsEnabled="{Binding Idle}" Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[6]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:PenguinReportSettingsUserControl IsEnabled="{Binding Idle}" Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[7]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[5]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:ConnectSettingsUserControl IsEnabled="{Binding Idle}" Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[6]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:StartSettingsUserControl Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[7]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:TimerSettingsUserControl Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[8]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:ToastSettingsUserControl IsEnabled="{Binding Idle}" Margin="20" />
<local:ToastSettingsUserControl Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[9]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:VersionUpdateSettingsUserControl IsEnabled="{Binding Idle}" Margin="20" />
<local:VersionUpdateSettingsUserControl Margin="20" />
<Rectangle HorizontalAlignment="Stretch" Fill="LightGray" Height="1" />
<TextBlock Style="{StaticResource TextBlockDefault}" Text="{Binding ListTitle[10]}" Foreground="Gray" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Left" />
<local:AboutUserControl Margin="20" />