mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-16 01:40:46 +08:00
提交新的改动
This commit is contained in:
@@ -33,6 +33,7 @@ MAA 会以 1 秒的间隔持续轮询这个端点,尝试获取他要执行的
|
||||
{
|
||||
"tasks": // 需要让MAA执行的Task的列表,目前可以支持的类型如示例中所示,如果不存在tasks则视为连接无效。
|
||||
[
|
||||
// 顺序执行的任务:下面这些任务会按照下发的顺序排队执行
|
||||
{
|
||||
"id": "b353c469-b902-4357-bd8f-d133199eea31", //任务的唯一id,字符串类型,在汇报任务时会使用
|
||||
"type": "CaptureImage", //截图任务,会截取一张当前模拟器的截图,并以Base64字符串的形式放在汇报任务的payload里。如果你需要下发这种类型的任务,请务必注意你的端点可接受的最大请求大小,因为截图会有数十MB,会超过一般网关的默认大小限制。
|
||||
@@ -54,6 +55,19 @@ MAA 会以 1 秒的间隔持续轮询这个端点,尝试获取他要执行的
|
||||
"type": "Settings-ConnectionAddress", //修改配置项的任务,等同于执行ConfigurationHelper.SetValue("ConnectionAddress", params); 为了安全起见,不是每个配置都可以修改,能修改的配置详见下述。
|
||||
"params": "value" //要修改的值
|
||||
},
|
||||
// 立即执行任务:下面这些任务可以在顺序执行任务运行中执行,并且MAA保证下面的任何一个任务都会尽快返回结果,通常用于对远程控制功能本身的控制。
|
||||
{
|
||||
"id": "b353c469-b902-4357-bd8f-d133199eea31", //任务的唯一id,字符串类型,在汇报任务时会使用
|
||||
"type": "CaptureImageNow", //立刻截图任务,和上面的截图任务是基本一样的,唯一的区别是这个任务会立刻被运行,而不会等待其他任务。
|
||||
},
|
||||
{
|
||||
"id": "b353c469-b902-4357-bd8f-d133199eea31", //任务的唯一id,字符串类型,在汇报任务时会使用
|
||||
"type": "StopTask", //"结束当前任务"任务,将会尝试结束当前运行的任务。如果任务列表还有其他任务会继续开始执行下一个。该任务不会等待并确认当前任务已停止才会返回,因此请使用心跳任务来确认停止命令是否已生效。
|
||||
},
|
||||
{
|
||||
"id": "b353c469-b902-4357-bd8f-d133199eea31", //任务的唯一id,字符串类型,在汇报任务时会使用
|
||||
"type": "HeartBeat", //心跳任务,该任务会立即返回,并且将当前“顺序执行的任务”队列中正在执行的任务的Id作为Payload返回,如果当前没有任务执行,返回空字符串。
|
||||
},
|
||||
],
|
||||
... // 如果你的这个端点还有其他用途,你可以自行添加可选的返回值,但是MAA只会读取tasks
|
||||
}
|
||||
@@ -64,8 +78,9 @@ MAA 会以 1 秒的间隔持续轮询这个端点,尝试获取他要执行的
|
||||
|
||||
::: note
|
||||
- LinkStart-[TaskName] 型的任务 type 的可选值为 LinkStart-Base,LinkStart-WakeUp,LinkStart-Combat,LinkStart-Recruiting,LinkStart-Mall,LinkStart-Mission,LinkStart-AutoRoguelike,LinkStart-ReclamationAlgorithm
|
||||
- Settings-[SettingsName] 型的任务的 type 的可选值为 Settings-ConnectionAddress
|
||||
- Settings-[SettingsName] 型的任务的 type 的可选值为 Settings-ConnectionAddress, Settings-Stage1
|
||||
- Settings 系列任务仍然是要按顺序执行的,并不会在收到任务的时候立刻执行,而是排在上一个任务的后面
|
||||
- 多个立即执行的任务也会按下发顺序执行,只不过这些任务的执行速度都很快,通常来说,并不需要关注他们的顺序。
|
||||
:::
|
||||
|
||||
## 汇报任务端点
|
||||
|
||||
@@ -26,11 +26,15 @@ 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 List<string> _enqueueTaskIds = new List<string>();
|
||||
private readonly ConcurrentQueue<JObject> _sequentialTaskQueue = new ConcurrentQueue<JObject>();
|
||||
private readonly ConcurrentQueue<JObject> _instantTaskQueue = new ConcurrentQueue<JObject>();
|
||||
private readonly Task _executeSequentialJobTask = Task.CompletedTask;
|
||||
private readonly Task _executeInstantJobTask = Task.CompletedTask;
|
||||
private readonly RunningState _runningState;
|
||||
|
||||
private string _currentSequentialTaskId = string.Empty;
|
||||
|
||||
public RemoteControlService()
|
||||
{
|
||||
_pollJobTask = _pollJobTask.ContinueWith(async _ =>
|
||||
@@ -51,14 +55,32 @@ namespace MaaWpfGui.Services.RemoteControl
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
});
|
||||
|
||||
_executeJobTask = _executeJobTask.ContinueWith(async _ =>
|
||||
_executeSequentialJobTask = _executeSequentialJobTask.ContinueWith(async _ =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
try
|
||||
{
|
||||
await ExecuteJobLoop();
|
||||
await ExecuteSequentialJobLoop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error(ex, "RemoteControl service raises unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
});
|
||||
|
||||
_executeInstantJobTask = _executeInstantJobTask.ContinueWith(async _ =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
try
|
||||
{
|
||||
await ExecuteInstantJobLoop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -193,6 +215,8 @@ namespace MaaWpfGui.Services.RemoteControl
|
||||
|
||||
#endregion
|
||||
|
||||
#region JobLoops
|
||||
|
||||
private async Task PollJobTaskLoop()
|
||||
{
|
||||
var endpoint = Instances.SettingsViewModel.RemoteControlGetTaskEndpointUri;
|
||||
@@ -226,20 +250,44 @@ namespace MaaWpfGui.Services.RemoteControl
|
||||
|
||||
// It is a valid task
|
||||
var id = task.GetValue("id")?.Value<string>();
|
||||
if (_executedTaskIds.Contains(id))
|
||||
if (_enqueueTaskIds.Contains(id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_executedTaskIds.Add(id);
|
||||
_taskQueue.Enqueue(task);
|
||||
_enqueueTaskIds.Add(id);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case "LinkStart":
|
||||
case "LinkStart-Base":
|
||||
case "LinkStart-WakeUp":
|
||||
case "LinkStart-Combat":
|
||||
case "LinkStart-Recruiting":
|
||||
case "LinkStart-Mall":
|
||||
case "LinkStart-Mission":
|
||||
case "LinkStart-AutoRoguelike":
|
||||
case "LinkStart-ReclamationAlgorithm":
|
||||
case "Toolbox-GachaOnce":
|
||||
case "Toolbox-GachaTenTimes":
|
||||
case "CaptureImage":
|
||||
case "Settings-ConnectAddress":
|
||||
case "Settings-Stage1":
|
||||
_sequentialTaskQueue.Enqueue(task);
|
||||
break;
|
||||
case "CaptureImageNow":
|
||||
case "HeartBeat":
|
||||
case "StopTask":
|
||||
_instantTaskQueue.Enqueue(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteJobLoop()
|
||||
private async Task ExecuteSequentialJobLoop()
|
||||
{
|
||||
if (_taskQueue.TryDequeue(out var task))
|
||||
if (_sequentialTaskQueue.TryDequeue(out var task))
|
||||
{
|
||||
var type = task.GetValue("type")?.Value<string>();
|
||||
var id = task.GetValue("id")?.Value<string>();
|
||||
@@ -247,6 +295,8 @@ namespace MaaWpfGui.Services.RemoteControl
|
||||
var payload = string.Empty;
|
||||
var status = "SUCCESS";
|
||||
|
||||
_currentSequentialTaskId = id;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case "LinkStart":
|
||||
@@ -343,8 +393,106 @@ namespace MaaWpfGui.Services.RemoteControl
|
||||
{
|
||||
Instances.SettingsViewModel.ConnectAddress = data;
|
||||
});
|
||||
|
||||
break;
|
||||
case "Settings-Stage1":
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Instances.TaskQueueViewModel.Stage1 = data;
|
||||
});
|
||||
break;
|
||||
|
||||
// ReSharper disable once RedundantEmptySwitchSection
|
||||
default:
|
||||
// 未知的Type统一直接发给MAACore
|
||||
// No! 未知的任务一概不处理
|
||||
break;
|
||||
}
|
||||
|
||||
var endpoint = Instances.SettingsViewModel.RemoteControlReportStatusUri;
|
||||
if (!string.IsNullOrWhiteSpace(endpoint) && endpoint.ToLower().StartsWith("https://"))
|
||||
{
|
||||
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,
|
||||
task = id,
|
||||
payload,
|
||||
});
|
||||
if (response == null)
|
||||
{
|
||||
Log.Logger.Error("RemoteControlService report task failed.");
|
||||
}
|
||||
}
|
||||
|
||||
_currentSequentialTaskId = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteInstantJobLoop()
|
||||
{
|
||||
if (_instantTaskQueue.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 "HeartBeat":
|
||||
{
|
||||
payload = _currentSequentialTaskId;
|
||||
break;
|
||||
}
|
||||
|
||||
case "StopTask":
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (!Instances.AsstProxy.AsstStop())
|
||||
{
|
||||
// 无法确定当前的界面,找不到借用的UI位置,因此只能Log
|
||||
Log.Logger.Error("Failed to stop Asst.");
|
||||
}
|
||||
});
|
||||
|
||||
// 无需等待,甩出任务即可返回,远端应该用心跳来确认界面卡死和取消是否成功。
|
||||
break;
|
||||
}
|
||||
|
||||
case "CaptureImageNow":
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
status = "FAILED";
|
||||
break;
|
||||
}
|
||||
|
||||
// ReSharper disable once RedundantEmptySwitchSection
|
||||
default:
|
||||
@@ -374,6 +522,8 @@ namespace MaaWpfGui.Services.RemoteControl
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 根据"一键长草"功能进行修改的方法。
|
||||
/// </summary>
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Center"
|
||||
Block.TextAlignment="Center"
|
||||
Text="{DynamicResource RemoteControlTooltips}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
Reference in New Issue
Block a user