mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-18 18:20:39 +08:00
远程控制功能
This commit is contained in:
@@ -1679,6 +1679,38 @@
|
||||
"sortId": 30001,
|
||||
"usage": "一份椒盐果仁的糖皮月饼,可用于恢复理智。"
|
||||
},
|
||||
"ap_supply_lt_120_2023_1": {
|
||||
"classifyType": "CONSUME",
|
||||
"description": "可口凉爽的冰皮月饼,记得冷藏保存哦!",
|
||||
"icon": "ap_supply_lt_120_2023_1.png",
|
||||
"name": "“满庭光”",
|
||||
"sortId": 30001,
|
||||
"usage": "一份芒果椰蓉馅的冰皮月饼,可用于恢复理智。"
|
||||
},
|
||||
"ap_supply_lt_120_2023_2": {
|
||||
"classifyType": "CONSUME",
|
||||
"description": "可口凉爽的冰皮月饼,记得冷藏保存哦!",
|
||||
"icon": "ap_supply_lt_120_2023_2.png",
|
||||
"name": "“良宵晴”",
|
||||
"sortId": 30001,
|
||||
"usage": "一份肉松馅的冰皮月饼,可用于恢复理智。"
|
||||
},
|
||||
"ap_supply_lt_120_2023_3": {
|
||||
"classifyType": "CONSUME",
|
||||
"description": "香甜脆爽的糖皮月饼,食用前记得加热哦!",
|
||||
"icon": "ap_supply_lt_120_2023_3.png",
|
||||
"name": "“飘桂香”",
|
||||
"sortId": 30001,
|
||||
"usage": "一份豆沙桂花馅的糖皮月饼,可用于恢复理智。"
|
||||
},
|
||||
"ap_supply_lt_120_2023_4": {
|
||||
"classifyType": "CONSUME",
|
||||
"description": "香甜脆爽的糖皮月饼,食用前记得加热哦!",
|
||||
"icon": "ap_supply_lt_120_2023_4.png",
|
||||
"name": "“藏金波“",
|
||||
"sortId": 30001,
|
||||
"usage": "一份咸蛋黄馅的糖皮月饼,可用于恢复理智。"
|
||||
},
|
||||
"ap_supply_lt_60": {
|
||||
"classifyType": "CONSUME",
|
||||
"description": "虽然暴饮暴食可以缓解战场带来的焦虑与压力,但总归不利于博士的身体健康。本品含有一定糖分,故而外包装采取特制结构,较难拆解,请借此消耗掉多余的卡路里。",
|
||||
|
||||
@@ -163,6 +163,11 @@ namespace MaaWpfGui.Constants
|
||||
public const string DropsItemName = "MainFunction.Drops.ItemName";
|
||||
public const string DropsQuantity = "MainFunction.Drops.Quantity";
|
||||
|
||||
public const string RemoteControlGetTaskEndpointUri = "RemoteControl.RemoteControlGetTaskEndpointUri";
|
||||
public const string RemoteControlReportStatusUri = "RemoteControl.RemoteControlReportStatusUri";
|
||||
public const string RemoteControlUserIdentity = "RemoteControl.RemoteControlUserIdentity";
|
||||
public const string RemoteControlDeviceIdentity = "RemoteControl.RemoteControlDeviceIdentity";
|
||||
|
||||
public const string ExternalNotificationEnabled = "ExternalNotification.Enabled";
|
||||
public const string ExternalNotificationSmtpServer = "ExternalNotification.Smtp.Server";
|
||||
public const string ExternalNotificationSmtpPort = "ExternalNotification.Smtp.Port";
|
||||
|
||||
@@ -16,6 +16,7 @@ using MaaWpfGui.Main;
|
||||
using MaaWpfGui.Services;
|
||||
using MaaWpfGui.Services.HotKeys;
|
||||
using MaaWpfGui.Services.Managers;
|
||||
using MaaWpfGui.Services.RemoteControl;
|
||||
using MaaWpfGui.Services.Web;
|
||||
using MaaWpfGui.ViewModels.UI;
|
||||
using Stylet;
|
||||
@@ -50,6 +51,8 @@ namespace MaaWpfGui.Helper
|
||||
|
||||
public static IMaaHotKeyActionHandler MaaHotKeyActionHandler { get; private set; }
|
||||
|
||||
public static RemoteControlService RemoteControlService { get; private set; }
|
||||
|
||||
public static IMainWindowManager MainWindowManager { get; private set; }
|
||||
|
||||
public static IHttpService HttpService { get; private set; }
|
||||
@@ -71,6 +74,8 @@ namespace MaaWpfGui.Helper
|
||||
HttpService = container.Get<HttpService>();
|
||||
MaaApiService = container.Get<MaaApiService>();
|
||||
|
||||
RemoteControlService = container.Get<RemoteControlService>();
|
||||
|
||||
HotKeyManager = container.Get<HotKeyManager>();
|
||||
MaaHotKeyManager = container.Get<MaaHotKeyManager>();
|
||||
MaaHotKeyActionHandler = container.Get<MaaHotKeyActionHandler>();
|
||||
|
||||
@@ -23,6 +23,7 @@ using MaaWpfGui.Helper;
|
||||
using MaaWpfGui.Services;
|
||||
using MaaWpfGui.Services.HotKeys;
|
||||
using MaaWpfGui.Services.Managers;
|
||||
using MaaWpfGui.Services.RemoteControl;
|
||||
using MaaWpfGui.Services.Web;
|
||||
using MaaWpfGui.ViewModels.UI;
|
||||
using MaaWpfGui.Views.UI;
|
||||
@@ -171,6 +172,8 @@ namespace MaaWpfGui.Main
|
||||
builder.Bind<IMaaHotKeyManager>().To<MaaHotKeyManager>().InSingletonScope();
|
||||
builder.Bind<IMaaHotKeyActionHandler>().To<MaaHotKeyActionHandler>().InSingletonScope();
|
||||
|
||||
builder.Bind<RemoteControlService>().To<RemoteControlService>().InSingletonScope();
|
||||
|
||||
builder.Bind<IMainWindowManager>().To<MainWindowManager>().InSingletonScope();
|
||||
|
||||
builder.Bind<IHttpService>().To<HttpService>().InSingletonScope();
|
||||
|
||||
@@ -234,6 +234,13 @@
|
||||
<system:String x:Key="AdditionCommand">附加命令</system:String>
|
||||
<system:String x:Key="StartsWithScript">开始前脚本</system:String>
|
||||
<system:String x:Key="EndsWithScript">结束后脚本</system:String>
|
||||
<system:String x:Key="RemoteControlSettings">远程控制</system:String>
|
||||
<system:String x:Key="RemoteControlDeviceIdentityLabel">设备标识符(只读)</system:String>
|
||||
<system:String x:Key="RemoteControlConnectionTest">测试连接</system:String>
|
||||
<system:String x:Key="RemoteControlRegenerateDeviceIdentity">重新生成</system:String>
|
||||
<system:String x:Key="RemoteControlUserIdentityLabel">用户标识符</system:String>
|
||||
<system:String x:Key="RemoteControlGetTaskEndpointLabel">获取任务端点</system:String>
|
||||
<system:String x:Key="RemoteControlReportStatusEndpointLabel">汇报任务端点</system:String>
|
||||
<system:String x:Key="RoguelikeTheme">肉鸽主题</system:String>
|
||||
<system:String x:Key="RoguelikeThemePhantom">傀影</system:String>
|
||||
<system:String x:Key="RoguelikeThemeMizuki">水月</system:String>
|
||||
@@ -663,6 +670,12 @@
|
||||
<system:String x:Key="GameResourceUpdated">游戏资源已更新,请重启 MAA</system:String>
|
||||
<system:String x:Key="GameResourceUpdating">游戏资源正在更新,请勿关闭 MAA</system:String>
|
||||
<!-- Api -->
|
||||
<!-- Remote Control -->
|
||||
<system:String x:Key="RemoteControlConnectionTestSuccess">连接测试成功!</system:String>
|
||||
<system:String x:Key="RemoteControlConnectionTestFail">连接测试失败。</system:String>
|
||||
<system:String x:Key="RemoteControlReceivedTask">收到远端任务{0},任务Id:{1}。</system:String>
|
||||
<system:String x:Key="RemoteControlCompletedTask">完成远端任务{0},任务Id:{1}。</system:String>
|
||||
<!-- Remote Control -->
|
||||
<!-- External Notification -->
|
||||
<system:String x:Key="ExternalNotificationEmailTemplateHello">博士,有新的通知哦!</system:String>
|
||||
<system:String x:Key="ExternalNotificationEmailTemplateFooterLineOne">您会收到此邮件,是因为您在 MAA 中设置了 SMTP 服务器并开启了邮件通知服务。</system:String>
|
||||
|
||||
496
src/MaaWpfGui/Services/RemoteControl/RemoteControlService.cs
Normal file
496
src/MaaWpfGui/Services/RemoteControl/RemoteControlService.cs
Normal file
@@ -0,0 +1,496 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using MaaWpfGui.Constants;
|
||||
using MaaWpfGui.Helper;
|
||||
using MaaWpfGui.States;
|
||||
using MaaWpfGui.ViewModels.UI;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serilog;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
||||
|
||||
namespace MaaWpfGui.Services.RemoteControl
|
||||
{
|
||||
public class RemoteControlService
|
||||
{
|
||||
private readonly Task _pollJobTask = Task.CompletedTask;
|
||||
private readonly Task _executeJobTask = Task.CompletedTask;
|
||||
private readonly List<string> _executedTaskIds = new List<string>();
|
||||
private readonly ConcurrentQueue<JObject> _taskQueue = new ConcurrentQueue<JObject>();
|
||||
private readonly RunningState _runningState;
|
||||
|
||||
public RemoteControlService()
|
||||
{
|
||||
_pollJobTask = _pollJobTask.ContinueWith(async (_) =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
try
|
||||
{
|
||||
await PollJobTaskLoop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error(ex, "RemoteControl service raises unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
});
|
||||
|
||||
_executeJobTask = _executeJobTask.ContinueWith(async (_) =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
try
|
||||
{
|
||||
await ExecuteJobLoop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error(ex, "RemoteControl service raises unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
});
|
||||
|
||||
_runningState = RunningState.Instance;
|
||||
}
|
||||
|
||||
#region Private Method Invoker
|
||||
|
||||
private static void InvokeInstanceMethod(object instance, string methodName)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(instance));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(methodName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(methodName));
|
||||
}
|
||||
|
||||
Type type = instance.GetType();
|
||||
MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"Method '{methodName}' not found in type '{type.FullName}'.");
|
||||
}
|
||||
|
||||
methodInfo.Invoke(instance, null);
|
||||
}
|
||||
|
||||
private static T InvokeInstanceFunction<T>(object instance, string methodName)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(instance));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(methodName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(methodName));
|
||||
}
|
||||
|
||||
Type type = instance.GetType();
|
||||
MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"Method '{methodName}' not found in type '{type.FullName}'.");
|
||||
}
|
||||
|
||||
if (!typeof(T).IsAssignableFrom(methodInfo.ReturnType))
|
||||
{
|
||||
throw new ArgumentException($"Method '{methodName}' is not {typeof(T)}.");
|
||||
}
|
||||
|
||||
return (T)methodInfo.Invoke(instance, null);
|
||||
}
|
||||
|
||||
private static async Task<T> InvokeInstanceAsyncFunction<T>(object instance, string methodName)
|
||||
{
|
||||
if (instance == null) { throw new ArgumentNullException(nameof(instance)); }
|
||||
if (string.IsNullOrEmpty(methodName)) { throw new ArgumentNullException(nameof(methodName)); }
|
||||
|
||||
Type type = instance.GetType();
|
||||
MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"Method '{methodName}' not found in type '{type.FullName}'.");
|
||||
}
|
||||
|
||||
// 检查方法是否是异步方法 (返回Task或Task<T>)
|
||||
if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
|
||||
{
|
||||
throw new ArgumentException($"Method '{methodName}' is not asynchronous.");
|
||||
}
|
||||
|
||||
return await (Task<T>)methodInfo.Invoke(instance, null);
|
||||
}
|
||||
|
||||
private static TResult InvokeStaticFunction<TResult>(Type staticType, string methodName)
|
||||
{
|
||||
if (staticType == null) { throw new ArgumentNullException(nameof(staticType)); }
|
||||
|
||||
if (string.IsNullOrEmpty(methodName)) { throw new ArgumentNullException(nameof(methodName)); }
|
||||
|
||||
MethodInfo methodInfo = staticType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"Method '{methodName}' not found in type '{staticType.FullName}'.");
|
||||
}
|
||||
|
||||
return (TResult)methodInfo.Invoke(null, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private async Task PollJobTaskLoop()
|
||||
{
|
||||
var endpoint = Instances.SettingsViewModel.RemoteControlGetTaskEndpointUri;
|
||||
var uid = Instances.SettingsViewModel.RemoteControlUserIdentity;
|
||||
var did = Instances.SettingsViewModel.RemoteControlDeviceIdentity;
|
||||
var response = await Instances.HttpService.PostAsJsonAsync(new Uri(endpoint), new { user=uid, device = did});
|
||||
if (response == null)
|
||||
{
|
||||
Log.Logger.Error("RemoteControlService endpoint failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
var jsonObject = JsonConvert.DeserializeObject<JObject>(response);
|
||||
|
||||
// A list of task
|
||||
if (jsonObject?.GetValue("tasks") is JArray tasks)
|
||||
{
|
||||
foreach (var task in tasks.OfType<JObject>())
|
||||
{
|
||||
var type = task.GetValue("type")?.Value<string>();
|
||||
if (!string.IsNullOrWhiteSpace(type))
|
||||
{
|
||||
// It is a valid task
|
||||
var id = task.GetValue("id")?.Value<string>();
|
||||
if (!_executedTaskIds.Contains(id))
|
||||
{
|
||||
_executedTaskIds.Add(id);
|
||||
|
||||
_taskQueue.Enqueue(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteJobLoop()
|
||||
{
|
||||
if (_taskQueue.TryDequeue(out var task))
|
||||
{
|
||||
var type = task.GetValue("type")?.Value<string>();
|
||||
var id = task.GetValue("id")?.Value<string>();
|
||||
var data = task.GetValue("params")?.Value<string>();
|
||||
var payload = string.Empty;
|
||||
var status = "SUCCESS";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case "LinkStart":
|
||||
{
|
||||
// 一键长草特殊任务
|
||||
await _runningState.UntilIdleAsync();
|
||||
var startLogStr = string.Format(LocalizationHelper.GetString("RemoteControlReceivedTask"), type, id);
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Instances.TaskQueueViewModel.AddLog(startLogStr);
|
||||
Instances.TaskQueueViewModel.LinkStart();
|
||||
});
|
||||
await _runningState.UntilIdleAsync();
|
||||
|
||||
var stopLogStr = string.Format(LocalizationHelper.GetString("RemoteControlCompletedTask"), type, id);
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Instances.TaskQueueViewModel.AddLog(stopLogStr);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case "LinkStart-Base":
|
||||
case "LinkStart-WakeUp":
|
||||
case "LinkStart-Combat":
|
||||
case "LinkStart-Recruiting":
|
||||
case "LinkStart-Mall":
|
||||
case "LinkStart-Mission":
|
||||
case "LinkStart-AutoRoguelike":
|
||||
case "LinkStart-ReclamationAlgorithm":
|
||||
{
|
||||
await LinkStart(new[] { type.Split('-')[1] });
|
||||
break;
|
||||
}
|
||||
|
||||
case "Toolbox-GachaOnce":
|
||||
{
|
||||
await _runningState.UntilIdleAsync();
|
||||
Instances.RecognizerViewModel.GachaOnce();
|
||||
while (!Instances.RecognizerViewModel.GachaDone)
|
||||
{
|
||||
await Task.Delay(100); // 暂停100毫秒以避免密集循环
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "Toolbox-GachaTenTimes":
|
||||
{
|
||||
await _runningState.UntilIdleAsync();
|
||||
Instances.RecognizerViewModel.GachaTenTimes();
|
||||
while (!Instances.RecognizerViewModel.GachaDone)
|
||||
{
|
||||
await Task.Delay(100); // 暂停100毫秒以避免密集循环
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "CaptureImage":
|
||||
{
|
||||
string errMsg = string.Empty;
|
||||
bool connected = await Task.Run(() => Instances.AsstProxy.AsstConnect(ref errMsg));
|
||||
if (connected)
|
||||
{
|
||||
var image = Instances.AsstProxy.AsstGetImage();
|
||||
if (image == null)
|
||||
{
|
||||
status = "FAILED";
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
PngBitmapEncoder encoder = new PngBitmapEncoder();
|
||||
encoder.Frames.Add(BitmapFrame.Create(image));
|
||||
encoder.Save(stream);
|
||||
bytes = stream.ToArray();
|
||||
}
|
||||
|
||||
payload = Convert.ToBase64String(bytes);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = "FAILED";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case "Settings-ConnectAddress":
|
||||
// ConfigurationHelper.SetValue(type.Split('-')[1], data);
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Instances.SettingsViewModel.ConnectAddress = data;
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// 未知的Type统一直接发给MAACore
|
||||
// No! 未知的任务一概不处理
|
||||
break;
|
||||
}
|
||||
|
||||
var endpoint = Instances.SettingsViewModel.RemoteControlReportStatusUri;
|
||||
var uid = Instances.SettingsViewModel.RemoteControlUserIdentity;
|
||||
var did = Instances.SettingsViewModel.RemoteControlDeviceIdentity;
|
||||
var response = await Instances.HttpService.PostAsJsonAsync(new Uri(endpoint), new
|
||||
{
|
||||
user = uid,
|
||||
device = did,
|
||||
status = status,
|
||||
task = id,
|
||||
payload = payload,
|
||||
});
|
||||
if (response == null)
|
||||
{
|
||||
Log.Logger.Error("RemoteControlService report task failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据"一键长草"功能进行修改的方法。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>注意以下特点:</para>
|
||||
/// <para>- 可以在非UI线程执行。</para>
|
||||
/// <para>- 不调用StartScript。</para>
|
||||
/// <para>- 不使用Model里的列表。</para>
|
||||
/// <para>- 在结尾添加对RunningStatus的等待。</para>
|
||||
/// <para>若"一键长草"功能在未来有更新,此方法也应进行相应的同步更新,但需确保上述特点保持不变。</para>
|
||||
/// </remarks>
|
||||
/// <param name="originalNames">指定的任务列表。</param>
|
||||
/// <returns>异步任务,无返回结果。</returns>
|
||||
public async Task LinkStart(IEnumerable<string> originalNames)
|
||||
{
|
||||
await _runningState.UntilIdleAsync();
|
||||
|
||||
_runningState.SetIdle(false);
|
||||
|
||||
await Application.Current.Dispatcher.Invoke(async () =>
|
||||
{
|
||||
|
||||
// 虽然更改时已经保存过了,不过保险起见还是在点击开始之后再保存一次任务及基建列表
|
||||
Instances.TaskQueueViewModel.TaskItemSelectionChanged();
|
||||
Instances.SettingsViewModel.InfrastOrderSelectionChanged();
|
||||
|
||||
InvokeInstanceMethod(Instances.TaskQueueViewModel, "ClearLog");
|
||||
|
||||
/*await Task.Run(() => Instances.SettingsViewModel.RunScript("StartsWithScript"));*/
|
||||
|
||||
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("ConnectingToEmulator"));
|
||||
if (!Instances.SettingsViewModel.AdbReplaced && !Instances.SettingsViewModel.IsAdbTouchMode())
|
||||
{
|
||||
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("AdbReplacementTips"), UiLogColor.Info);
|
||||
}
|
||||
|
||||
// 一般是点了“停止”按钮了
|
||||
if (Instances.TaskQueueViewModel.Stopping)
|
||||
{
|
||||
Instances.TaskQueueViewModel.SetStopped();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await InvokeInstanceAsyncFunction<bool>(Instances.TaskQueueViewModel, "ConnectToEmulator"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 一般是点了“停止”按钮了
|
||||
if (Instances.TaskQueueViewModel.Stopping)
|
||||
{
|
||||
Instances.TaskQueueViewModel.SetStopped();
|
||||
return;
|
||||
}
|
||||
|
||||
bool taskRet = true;
|
||||
|
||||
// 直接遍历TaskItemViewModels里面的内容,是排序后的
|
||||
int count = 0;
|
||||
foreach (var item in originalNames)
|
||||
{
|
||||
++count;
|
||||
switch (item)
|
||||
{
|
||||
case "Base":
|
||||
taskRet &= InvokeInstanceFunction<bool>(Instances.TaskQueueViewModel, "AppendInfrast");
|
||||
break;
|
||||
|
||||
case "WakeUp":
|
||||
taskRet &= InvokeStaticFunction<bool>(Instances.TaskQueueViewModel.GetType(), "AppendStart");
|
||||
break;
|
||||
|
||||
case "Combat":
|
||||
taskRet &= InvokeInstanceFunction<bool>(Instances.TaskQueueViewModel, "AppendFight");
|
||||
break;
|
||||
|
||||
case "Recruiting":
|
||||
taskRet &= InvokeStaticFunction<bool>(Instances.TaskQueueViewModel.GetType(), "AppendRecruit");
|
||||
break;
|
||||
|
||||
case "Mall":
|
||||
taskRet &= InvokeInstanceFunction<bool>(Instances.TaskQueueViewModel, "AppendMall");
|
||||
break;
|
||||
|
||||
case "Mission":
|
||||
taskRet &= InvokeInstanceFunction<bool>(Instances.TaskQueueViewModel, "AppendAward");
|
||||
break;
|
||||
|
||||
case "AutoRoguelike":
|
||||
taskRet &= InvokeStaticFunction<bool>(Instances.TaskQueueViewModel.GetType(), "AppendRoguelike");
|
||||
break;
|
||||
|
||||
case "ReclamationAlgorithm":
|
||||
taskRet &= InvokeStaticFunction<bool>(Instances.TaskQueueViewModel.GetType(), "AppendReclamation");
|
||||
break;
|
||||
|
||||
default:
|
||||
--count;
|
||||
|
||||
// Instances.TaskQueueViewModel._logger.Error("Unknown task: " + item);
|
||||
break;
|
||||
}
|
||||
|
||||
if (taskRet)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Instances.TaskQueueViewModel.AddLog(item + "Error", UiLogColor.Error);
|
||||
taskRet = true;
|
||||
--count;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("UnselectedTask"));
|
||||
_runningState.SetIdle(true);
|
||||
Instances.TaskQueueViewModel.SetStopped();
|
||||
return;
|
||||
}
|
||||
|
||||
taskRet &= Instances.AsstProxy.AsstStart();
|
||||
|
||||
if (taskRet)
|
||||
{
|
||||
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("Running"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("UnknownErrorOccurs"));
|
||||
await Instances.TaskQueueViewModel.Stop();
|
||||
Instances.TaskQueueViewModel.SetStopped();
|
||||
}
|
||||
});
|
||||
|
||||
await _runningState.UntilIdleAsync();
|
||||
}
|
||||
|
||||
public static async Task ConnectionTest()
|
||||
{
|
||||
var endpoint = Instances.SettingsViewModel.RemoteControlGetTaskEndpointUri;
|
||||
var uid = Instances.SettingsViewModel.RemoteControlUserIdentity;
|
||||
var did = Instances.SettingsViewModel.RemoteControlDeviceIdentity;
|
||||
var response = await Instances.HttpService.PostAsJsonAsync(new Uri(endpoint), new { user = uid, device = did });
|
||||
|
||||
using var toast = new ToastNotification(
|
||||
LocalizationHelper.GetString(
|
||||
response != null ? "RemoteControlConnectionTestSuccess" : "RemoteControlConnectionTestFail"));
|
||||
|
||||
// if (response != null)
|
||||
// {
|
||||
// toast.AppendContentText(response);
|
||||
// }
|
||||
toast.Show();
|
||||
|
||||
}
|
||||
|
||||
public static void RegenerateDeviceIdentity()
|
||||
{
|
||||
Instances.SettingsViewModel.RemoteControlDeviceIdentity = Guid.NewGuid().ToString("N");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ using MaaWpfGui.Main;
|
||||
using MaaWpfGui.Models;
|
||||
using MaaWpfGui.Services.HotKeys;
|
||||
using MaaWpfGui.Services.Notification;
|
||||
using MaaWpfGui.Services.RemoteControl;
|
||||
using MaaWpfGui.States;
|
||||
using MaaWpfGui.Utilities;
|
||||
using MaaWpfGui.Utilities.ValueType;
|
||||
@@ -106,6 +107,7 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
_listTitle.Add(LocalizationHelper.GetString("ConnectionSettings"));
|
||||
_listTitle.Add(LocalizationHelper.GetString("StartupSettings"));
|
||||
_listTitle.Add(LocalizationHelper.GetString("UISettings"));
|
||||
_listTitle.Add(LocalizationHelper.GetString("RemoteControlSettings"));
|
||||
_listTitle.Add(LocalizationHelper.GetString("ExternalNotificationSettings"));
|
||||
_listTitle.Add(LocalizationHelper.GetString("HotKeySettings"));
|
||||
_listTitle.Add(LocalizationHelper.GetString("UpdateSettings"));
|
||||
@@ -150,6 +152,69 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
}
|
||||
}
|
||||
|
||||
#region Remote Control
|
||||
|
||||
public async void RemoteControlConnectionTest()
|
||||
{
|
||||
await RemoteControlService.ConnectionTest();
|
||||
}
|
||||
|
||||
public void RemoteControlRegenerateDeviceIdentity()
|
||||
{
|
||||
RemoteControlService.RegenerateDeviceIdentity();
|
||||
}
|
||||
|
||||
private string _remoteControlGetTaskEndpointUri = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlGetTaskEndpointUri, string.Empty);
|
||||
|
||||
public string RemoteControlGetTaskEndpointUri
|
||||
{
|
||||
get => _remoteControlGetTaskEndpointUri;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _remoteControlGetTaskEndpointUri, value);
|
||||
ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlGetTaskEndpointUri, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _remoteControlReportStatusUri = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlReportStatusUri, string.Empty);
|
||||
|
||||
public string RemoteControlReportStatusUri
|
||||
{
|
||||
get => _remoteControlReportStatusUri;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _remoteControlReportStatusUri, value);
|
||||
ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlReportStatusUri, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _remoteControlUserIdentity = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlUserIdentity, string.Empty);
|
||||
|
||||
public string RemoteControlUserIdentity
|
||||
{
|
||||
get => _remoteControlUserIdentity;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _remoteControlUserIdentity, value);
|
||||
ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlUserIdentity, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string _remoteControlDeviceIdentity = ConfigurationHelper.GetValue(ConfigurationKeys.RemoteControlDeviceIdentity, string.Empty);
|
||||
|
||||
public string RemoteControlDeviceIdentity
|
||||
{
|
||||
get => _remoteControlDeviceIdentity;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _remoteControlDeviceIdentity, value);
|
||||
ConfigurationHelper.SetValue(ConfigurationKeys.RemoteControlDeviceIdentity, value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region External Notifications
|
||||
|
||||
public void ExternalNotificationSendTest()
|
||||
@@ -406,6 +471,14 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
new CombinedData { Display = LocalizationHelper.GetString("RoguelikeThemeSami"), Value = "Sami" },
|
||||
};
|
||||
|
||||
RemoteControlList = new List<CombinedData>
|
||||
{
|
||||
new CombinedData { Display = LocalizationHelper.GetString("RemoteControlHandshakeUri"), Value = "Phantom" },
|
||||
new CombinedData { Display = LocalizationHelper.GetString("RemoteControlEndpointUri"), Value = "Mizuki" },
|
||||
new CombinedData { Display = LocalizationHelper.GetString("RemoteControlUserIdentity"), Value = "Sami" },
|
||||
new CombinedData { Display = LocalizationHelper.GetString("RemoteControlUserIdentity"), Value = "Sami" },
|
||||
};
|
||||
|
||||
UpdateRoguelikeSquadList();
|
||||
UpdateRoguelikeCoreCharList();
|
||||
|
||||
@@ -1206,6 +1279,11 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
/// </summary>
|
||||
public List<CombinedData> TouchModeList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of touch modes
|
||||
/// </summary>
|
||||
public List<CombinedData> RemoteControlList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of dark mode.
|
||||
/// </summary>
|
||||
|
||||
@@ -69,15 +69,18 @@
|
||||
<userControl:GUISettingsUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
|
||||
<hc:Divider Content="{Binding ListTitle[6]}" />
|
||||
<userControl:ExternalNotificationSettingsUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
<userControl:RemoteControlUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
|
||||
<hc:Divider Content="{Binding ListTitle[7]}" />
|
||||
<userControl:HotKeySettingsUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
<userControl:ExternalNotificationSettingsUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
|
||||
<hc:Divider Content="{Binding ListTitle[8]}" />
|
||||
<userControl:VersionUpdateSettingsUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
<userControl:HotKeySettingsUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
|
||||
<hc:Divider Content="{Binding ListTitle[9]}" />
|
||||
<userControl:VersionUpdateSettingsUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
|
||||
<hc:Divider Content="{Binding ListTitle[10]}" />
|
||||
<userControl:AboutUserControl Margin="0,20" HorizontalAlignment="Center" />
|
||||
<!--<Rectangle HorizontalAlignment="Stretch" Fill="{DynamicResource BorderBrush}" Height="1" />-->
|
||||
</StackPanel>
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
<UserControl
|
||||
x:Class="MaaWpfGui.Views.UserControl.RemoteControlUserControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:MaaWpfGui.ViewModels.UI"
|
||||
xmlns:controls="clr-namespace:MaaWpfGui.Styles.Controls"
|
||||
xmlns:calcBinding="clr-namespace:CalcBinding;assembly=CalcBinding"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
d:DataContext="{d:DesignInstance {x:Type ui:SettingsViewModel}}"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="550"
|
||||
mc:Ignorable="d">
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*" MinWidth="250"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Control Endpoint Input -->
|
||||
<controls:TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
Block.TextAlignment="Center"
|
||||
Text="{DynamicResource RemoteControlGetTaskEndpointLabel}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBox
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0,5,0,5"
|
||||
Text="{Binding RemoteControlGetTaskEndpointUri}" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- Handshake Endpoint Input -->
|
||||
<controls:TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
Block.TextAlignment="Center"
|
||||
Text="{DynamicResource RemoteControlReportStatusEndpointLabel}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBox
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="0,5,0,5"
|
||||
Text="{Binding RemoteControlReportStatusUri}" Grid.ColumnSpan="2"/>
|
||||
|
||||
<!-- User Identity Input -->
|
||||
<controls:TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
Block.TextAlignment="Center"
|
||||
Text="{DynamicResource RemoteControlUserIdentityLabel}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBox
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="0,5,0,5"
|
||||
Text="{Binding RemoteControlUserIdentity}"/>
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Margin="5"
|
||||
Command="{s:Action RemoteControlConnectionTest}"
|
||||
Content="{DynamicResource RemoteControlConnectionTest}"/>
|
||||
|
||||
<!-- Remote ID (Read-only & Copyable) -->
|
||||
<controls:TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
Block.TextAlignment="Center"
|
||||
Text="{DynamicResource RemoteControlDeviceIdentityLabel}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBox
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="0,5,0,5"
|
||||
Text="{Binding RemoteControlDeviceIdentity}"
|
||||
IsReadOnly="True"
|
||||
ContextMenuService.IsEnabled="False"/>
|
||||
<Button
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Margin="5"
|
||||
Command="{s:Action RemoteControlRegenerateDeviceIdentity}"
|
||||
Content="{DynamicResource RemoteControlRegenerateDeviceIdentity}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MaaWpfGui.Views.UserControl
|
||||
{
|
||||
/// <summary>
|
||||
/// RemoteControlUserControl.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class RemoteControlUserControl
|
||||
{
|
||||
public RemoteControlUserControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user