MaaFw 4.4.0a3__py3-none-macosx_13_0_x86_64.whl → 5.0.0b2__py3-none-macosx_13_0_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of MaaFw might be problematic. Click here for more details.

maa/agent/agent_server.py CHANGED
@@ -1,9 +1,8 @@
1
1
  import ctypes
2
- import sys
3
2
 
4
3
  from ..define import *
5
4
  from ..library import Library
6
- from ..buffer import StringBuffer
5
+ from ..event_sink import EventSink
7
6
 
8
7
 
9
8
  class AgentServer:
@@ -88,12 +87,94 @@ class AgentServer:
88
87
  Library.agent_server().MaaAgentServerJoin()
89
88
 
90
89
  @staticmethod
91
- def detach(self) -> None:
90
+ def detach() -> None:
92
91
 
93
92
  AgentServer._set_api_properties()
94
93
 
95
94
  Library.agent_server().MaaAgentServerDetach()
96
95
 
96
+ _sink_holder: Dict[int, "EventSink"] = {}
97
+
98
+ @staticmethod
99
+ def resource_sink():
100
+ def wrapper_sink(sink):
101
+ AgentServer.add_resource_sink(sink=sink())
102
+ return sink
103
+
104
+ return wrapper_sink
105
+
106
+ @staticmethod
107
+ def add_resource_sink(sink: "ResourceEventSink") -> None:
108
+ sink_id = int(
109
+ Library.agent_server().MaaAgentServerAddResourceSink(
110
+ *EventSink._gen_c_param(sink)
111
+ )
112
+ )
113
+ if sink_id == MaaInvalidId:
114
+ return None
115
+
116
+ AgentServer._sink_holder[sink_id] = sink
117
+
118
+ @staticmethod
119
+ def controller_sink():
120
+ def wrapper_sink(sink):
121
+ AgentServer.add_controller_sink(sink=sink())
122
+ return sink
123
+
124
+ return wrapper_sink
125
+
126
+ @staticmethod
127
+ def add_controller_sink(sink: "ControllerEventSink") -> None:
128
+ sink_id = int(
129
+ Library.agent_server().MaaAgentServerAddControllerSink(
130
+ *EventSink._gen_c_param(sink)
131
+ )
132
+ )
133
+ if sink_id == MaaInvalidId:
134
+ return None
135
+
136
+ AgentServer._sink_holder[sink_id] = sink
137
+
138
+ @staticmethod
139
+ def tasker_sink():
140
+ def wrapper_sink(sink):
141
+ AgentServer.add_tasker_sink(sink=sink())
142
+ return sink
143
+
144
+ return wrapper_sink
145
+
146
+ @staticmethod
147
+ def add_tasker_sink(sink: "TaskerEventSink") -> None:
148
+ sink_id = int(
149
+ Library.agent_server().MaaAgentServerAddTaskerSink(
150
+ *EventSink._gen_c_param(sink)
151
+ )
152
+ )
153
+ if sink_id == MaaInvalidId:
154
+ return None
155
+
156
+ AgentServer._sink_holder[sink_id] = sink
157
+
158
+ @staticmethod
159
+ def context_sink():
160
+ def wrapper_sink(sink):
161
+ AgentServer.add_context_sink(sink=sink())
162
+ return sink
163
+
164
+ return wrapper_sink
165
+
166
+ @staticmethod
167
+ def add_context_sink(sink: "ContextEventSink") -> None:
168
+ sink_id = int(
169
+ Library.agent_server().MaaAgentServerAddContextSink(
170
+ *EventSink._gen_c_param(sink)
171
+ )
172
+ )
173
+ if sink_id == MaaInvalidId:
174
+ return None
175
+
176
+ AgentServer._sink_holder[sink_id] = sink
177
+
97
178
  _api_properties_initialized: bool = False
98
179
 
99
180
  @staticmethod
@@ -130,3 +211,27 @@ class AgentServer:
130
211
 
131
212
  Library.agent_server().MaaAgentServerDetach.restype = None
132
213
  Library.agent_server().MaaAgentServerDetach.argtypes = []
214
+
215
+ Library.agent_server().MaaAgentServerAddResourceSink.restype = MaaSinkId
216
+ Library.agent_server().MaaAgentServerAddResourceSink.argtypes = [
217
+ MaaEventCallback,
218
+ ctypes.c_void_p,
219
+ ]
220
+
221
+ Library.agent_server().MaaAgentServerAddControllerSink.restype = MaaSinkId
222
+ Library.agent_server().MaaAgentServerAddControllerSink.argtypes = [
223
+ MaaEventCallback,
224
+ ctypes.c_void_p,
225
+ ]
226
+
227
+ Library.agent_server().MaaAgentServerAddTaskerSink.restype = MaaSinkId
228
+ Library.agent_server().MaaAgentServerAddTaskerSink.argtypes = [
229
+ MaaEventCallback,
230
+ ctypes.c_void_p,
231
+ ]
232
+
233
+ Library.agent_server().MaaAgentServerAddContextSink.restype = MaaSinkId
234
+ Library.agent_server().MaaAgentServerAddContextSink.argtypes = [
235
+ MaaEventCallback,
236
+ ctypes.c_void_p,
237
+ ]
maa/agent_client.py CHANGED
@@ -3,6 +3,8 @@ import ctypes
3
3
  from .define import *
4
4
  from .library import Library
5
5
  from .resource import Resource
6
+ from .controller import Controller
7
+ from .tasker import Tasker
6
8
  from .buffer import StringBuffer
7
9
 
8
10
 
@@ -47,6 +49,30 @@ class AgentClient:
47
49
  )
48
50
  )
49
51
 
52
+ def register_sink(
53
+ self, resource: Resource, controller: Controller, tasker: Tasker
54
+ ) -> bool:
55
+ # avoid gc
56
+ self._sinks = [resource, controller, tasker]
57
+
58
+ return (
59
+ bool(
60
+ Library.agent_client().MaaAgentClientRegisterResourceSink(
61
+ self._handle, resource._handle
62
+ )
63
+ )
64
+ and bool(
65
+ Library.agent_client().MaaAgentClientRegisterControllerSink(
66
+ self._handle, controller._handle
67
+ )
68
+ )
69
+ and bool(
70
+ Library.agent_client().MaaAgentClientRegisterTaskerSink(
71
+ self._handle, tasker._handle
72
+ )
73
+ )
74
+ )
75
+
50
76
  def connect(self) -> bool:
51
77
  return bool(Library.agent_client().MaaAgentClientConnect(self._handle))
52
78
 
@@ -62,7 +88,11 @@ class AgentClient:
62
88
  return bool(Library.agent_client().MaaAgentClientAlive(self._handle))
63
89
 
64
90
  def set_timeout(self, milliseconds: int) -> bool:
65
- return bool(Library.agent_client().MaaAgentClientSetTimeout(self._handle, ctypes.c_int64(milliseconds)))
91
+ return bool(
92
+ Library.agent_client().MaaAgentClientSetTimeout(
93
+ self._handle, ctypes.c_int64(milliseconds)
94
+ )
95
+ )
66
96
 
67
97
  _api_properties_initialized: bool = False
68
98
 
@@ -96,6 +126,24 @@ class AgentClient:
96
126
  MaaResourceHandle,
97
127
  ]
98
128
 
129
+ Library.agent_client().MaaAgentClientRegisterResourceSink.restype = MaaBool
130
+ Library.agent_client().MaaAgentClientRegisterResourceSink.argtypes = [
131
+ MaaAgentClientHandle,
132
+ MaaResourceHandle,
133
+ ]
134
+
135
+ Library.agent_client().MaaAgentClientRegisterControllerSink.restype = MaaBool
136
+ Library.agent_client().MaaAgentClientRegisterControllerSink.argtypes = [
137
+ MaaAgentClientHandle,
138
+ MaaControllerHandle,
139
+ ]
140
+
141
+ Library.agent_client().MaaAgentClientRegisterTaskerSink.restype = MaaBool
142
+ Library.agent_client().MaaAgentClientRegisterTaskerSink.argtypes = [
143
+ MaaAgentClientHandle,
144
+ MaaTaskerHandle,
145
+ ]
146
+
99
147
  Library.agent_client().MaaAgentClientConnect.restype = MaaBool
100
148
  Library.agent_client().MaaAgentClientConnect.argtypes = [
101
149
  MaaAgentClientHandle,
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
maa/bin/libMaaUtils.dylib CHANGED
Binary file
Binary file
Binary file
Binary file
maa/context.py CHANGED
@@ -1,13 +1,15 @@
1
1
  import ctypes
2
2
  import json
3
- from typing import Dict, Optional, Tuple
3
+ from typing import Any, Dict, Optional, Tuple, Union
4
4
 
5
5
  import numpy
6
6
 
7
+ from .event_sink import EventSink, NotificationType
7
8
  from .buffer import ImageBuffer, RectBuffer, StringBuffer, StringListBuffer
8
9
  from .define import *
9
10
  from .library import Library
10
11
  from .tasker import Tasker
12
+ from .pipeline import JPipelineData, JPipelineParser
11
13
  from .job import JobWithResult
12
14
 
13
15
 
@@ -32,6 +34,15 @@ class Context:
32
34
  def run_task(
33
35
  self, entry: str, pipeline_override: Dict = {}
34
36
  ) -> Optional[TaskDetail]:
37
+ """同步执行任务 / Synchronously execute task
38
+
39
+ Args:
40
+ entry: 任务入口 / Task entry
41
+ pipeline_override: 用于覆盖的 json / JSON for overriding
42
+
43
+ Returns:
44
+ Optional[TaskDetail]: 任务详情,执行失败则返回 None / Task detail, or None if execution failed
45
+ """
35
46
  task_id = int(
36
47
  Library.framework().MaaContextRunTask(
37
48
  self._handle, *Context._gen_post_param(entry, pipeline_override)
@@ -43,8 +54,24 @@ class Context:
43
54
  return self.tasker.get_task_detail(task_id)
44
55
 
45
56
  def run_recognition(
46
- self, entry: str, image: numpy.ndarray, pipeline_override: Dict = {}
57
+ self,
58
+ entry: str,
59
+ image: numpy.ndarray,
60
+ pipeline_override: Dict = {},
47
61
  ) -> Optional[RecognitionDetail]:
62
+ """同步执行识别逻辑 / Synchronously execute recognition logic
63
+
64
+ 不会执行后续操作, 不会执行后续 next
65
+ Will not execute subsequent operations or next steps
66
+
67
+ Args:
68
+ entry: 任务名 / Task name
69
+ image: 前序截图 / Previous screenshot
70
+ pipeline_override: 用于覆盖的 json / JSON for overriding
71
+
72
+ Returns:
73
+ Optional[RecognitionDetail]: 识别详情,执行失败则返回 None / Recognition detail, or None if execution failed
74
+ """
48
75
  image_buffer = ImageBuffer()
49
76
  image_buffer.set(image)
50
77
  reco_id = int(
@@ -66,6 +93,20 @@ class Context:
66
93
  reco_detail: str = "",
67
94
  pipeline_override: Dict = {},
68
95
  ) -> Optional[NodeDetail]:
96
+ """同步执行操作逻辑 / Synchronously execute action logic
97
+
98
+ 不会执行后续 next
99
+ Will not execute subsequent next steps
100
+
101
+ Args:
102
+ entry: 任务名 / Task name
103
+ box: 前序识别位置 / Previous recognition position
104
+ reco_detail: 前序识别详情 / Previous recognition details
105
+ pipeline_override: 用于覆盖的 json / JSON for overriding
106
+
107
+ Returns:
108
+ Optional[NodeDetail]: 节点详情,执行失败则返回 None / Node detail, or None if execution failed
109
+ """
69
110
  rect = RectBuffer()
70
111
  rect.set(box)
71
112
 
@@ -84,14 +125,36 @@ class Context:
84
125
  return self.tasker.get_node_detail(node_id)
85
126
 
86
127
  def override_pipeline(self, pipeline_override: Dict) -> bool:
128
+ """覆盖 pipeline / Override pipeline_override
129
+
130
+ Args:
131
+ pipeline_override: 用于覆盖的 json / JSON for overriding
132
+
133
+ Returns:
134
+ bool: 是否成功 / Whether successful
135
+ """
136
+ pipeline_json = json.dumps(pipeline_override, ensure_ascii=False)
137
+
87
138
  return bool(
88
139
  Library.framework().MaaContextOverridePipeline(
89
140
  self._handle,
90
- json.dumps(pipeline_override, ensure_ascii=False).encode(),
141
+ pipeline_json.encode(),
91
142
  )
92
143
  )
93
144
 
94
145
  def override_next(self, name: str, next_list: List[str]) -> bool:
146
+ """覆盖任务的 next 列表 / Override the next list of task
147
+
148
+ 如果节点不存在,此方法会失败
149
+ This method will fail if the node does not exist
150
+
151
+ Args:
152
+ name: 任务名 / Task name
153
+ next_list: next 列表 / Next list
154
+
155
+ Returns:
156
+ bool: 成功返回 True,如果节点不存在则返回 False / Returns True on success, False if node does not exist
157
+ """
95
158
  list_buffer = StringListBuffer()
96
159
  list_buffer.set(next_list)
97
160
 
@@ -101,7 +164,34 @@ class Context:
101
164
  )
102
165
  )
103
166
 
104
- def get_node_data(self, name: str) -> Optional[dict]:
167
+ def override_image(self, image_name: str, image: numpy.ndarray) -> bool:
168
+ """覆盖图片 / Override the image corresponding to image_name
169
+
170
+ Args:
171
+ image_name: 图片名 / Image name
172
+ image: 图片数据 / Image data
173
+
174
+ Returns:
175
+ bool: 是否成功 / Whether successful
176
+ """
177
+ image_buffer = ImageBuffer()
178
+ image_buffer.set(image)
179
+
180
+ return bool(
181
+ Library.framework().MaaContextOverrideImage(
182
+ self._handle, image_name.encode(), image_buffer._handle
183
+ )
184
+ )
185
+
186
+ def get_node_data(self, name: str) -> Optional[Dict]:
187
+ """获取任务当前的定义 / Get the current definition of task
188
+
189
+ Args:
190
+ name: 任务名 / Task name
191
+
192
+ Returns:
193
+ Optional[Dict]: 任务定义字典,如果不存在则返回 None / Task definition dict, or None if not exists
194
+ """
105
195
  string_buffer = StringBuffer()
106
196
  if not Library.framework().MaaContextGetNodeData(
107
197
  self._handle, name.encode(), string_buffer._handle
@@ -117,11 +207,32 @@ class Context:
117
207
  except json.JSONDecodeError:
118
208
  return None
119
209
 
210
+ def get_node_object(self, name: str) -> Optional[JPipelineData]:
211
+ node_data = self.get_node_data(name)
212
+
213
+ if not node_data:
214
+ return None
215
+
216
+ return JPipelineParser.parse_pipeline_data(node_data)
217
+
120
218
  @property
121
219
  def tasker(self) -> Tasker:
220
+ """获取实例 / Get instance
221
+
222
+ Returns:
223
+ Tasker: 实例对象 / Instance object
224
+ """
122
225
  return self._tasker
123
226
 
124
227
  def get_task_job(self) -> JobWithResult:
228
+ """获取对应任务号的任务作业 / Get task job for corresponding task id
229
+
230
+ Returns:
231
+ JobWithResult: 任务作业对象 / Task job object
232
+
233
+ Raises:
234
+ ValueError: 如果任务 id 为 None
235
+ """
125
236
  task_id = Library.framework().MaaContextGetTaskId(self._handle)
126
237
  if not task_id:
127
238
  raise ValueError("task_id is None")
@@ -129,6 +240,14 @@ class Context:
129
240
  return self.tasker._gen_task_job(task_id)
130
241
 
131
242
  def clone(self) -> "Context":
243
+ """复制上下文 / Clone context
244
+
245
+ Returns:
246
+ Context: 复制的上下文对象 / Cloned context object
247
+
248
+ Raises:
249
+ ValueError: 如果克隆失败
250
+ """
132
251
  cloned_handle = Library.framework().MaaContextClone(self._handle)
133
252
  if not cloned_handle:
134
253
  raise ValueError("cloned_handle is None")
@@ -145,9 +264,11 @@ class Context:
145
264
 
146
265
  @staticmethod
147
266
  def _gen_post_param(entry: str, pipeline_override: Dict) -> Tuple[bytes, bytes]:
267
+ pipeline_json = json.dumps(pipeline_override, ensure_ascii=False)
268
+
148
269
  return (
149
270
  entry.encode(),
150
- json.dumps(pipeline_override, ensure_ascii=False).encode(),
271
+ pipeline_json.encode(),
151
272
  )
152
273
 
153
274
  _api_properties_initialized: bool = False
@@ -196,6 +317,13 @@ class Context:
196
317
  MaaStringListBufferHandle,
197
318
  ]
198
319
 
320
+ Library.framework().MaaContextOverrideImage.restype = MaaBool
321
+ Library.framework().MaaContextOverrideImage.argtypes = [
322
+ MaaContextHandle,
323
+ ctypes.c_char_p,
324
+ MaaImageBufferHandle,
325
+ ]
326
+
199
327
  Library.framework().MaaContextGetNodeData.restype = MaaBool
200
328
  Library.framework().MaaContextGetNodeData.argtypes = [
201
329
  MaaContextHandle,
@@ -217,3 +345,87 @@ class Context:
217
345
  Library.framework().MaaContextClone.argtypes = [
218
346
  MaaContextHandle,
219
347
  ]
348
+
349
+
350
+ class ContextEventSink(EventSink):
351
+
352
+ @dataclass
353
+ class NodeNextListDetail:
354
+ task_id: int
355
+ name: str
356
+ next_list: list[str]
357
+ focus: Any
358
+
359
+ def on_node_next_list(
360
+ self,
361
+ context: Context,
362
+ noti_type: NotificationType,
363
+ detail: NodeNextListDetail,
364
+ ):
365
+ pass
366
+
367
+ @dataclass
368
+ class NodeRecognitionDetail:
369
+ task_id: int
370
+ reco_id: int
371
+ name: str
372
+ focus: Any
373
+
374
+ def on_node_recognition(
375
+ self,
376
+ context: Context,
377
+ noti_type: NotificationType,
378
+ detail: NodeRecognitionDetail,
379
+ ):
380
+ pass
381
+
382
+ @dataclass
383
+ class NodeActionDetail:
384
+ task_id: int
385
+ node_id: int
386
+ name: str
387
+ focus: Any
388
+
389
+ def on_node_action(
390
+ self, context: Context, noti_type: NotificationType, detail: NodeActionDetail
391
+ ):
392
+ pass
393
+
394
+ def on_raw_notification(self, context: Context, msg: str, details: dict):
395
+ pass
396
+
397
+ def _on_raw_notification(self, handle: ctypes.c_void_p, msg: str, details: dict):
398
+
399
+ context = Context(handle=handle)
400
+ self.on_raw_notification(context, msg, details)
401
+
402
+ noti_type = EventSink._notification_type(msg)
403
+ if msg.startswith("Node.NextList"):
404
+ detail = self.NodeNextListDetail(
405
+ task_id=details["task_id"],
406
+ name=details["name"],
407
+ next_list=details["list"],
408
+ focus=details["focus"],
409
+ )
410
+ self.on_node_next_list(context, noti_type, detail)
411
+
412
+ elif msg.startswith("Node.Recognition"):
413
+ detail = self.NodeRecognitionDetail(
414
+ task_id=details["task_id"],
415
+ reco_id=details["reco_id"],
416
+ name=details["name"],
417
+ focus=details["focus"],
418
+ )
419
+ self.on_node_recognition(context, noti_type, detail)
420
+
421
+ elif msg.startswith("Node.Action"):
422
+ detail = self.NodeActionDetail(
423
+ task_id=details["task_id"],
424
+ node_id=details["node_id"],
425
+ name=details["name"],
426
+ focus=details["focus"],
427
+ )
428
+ self.on_node_action(context, noti_type, detail)
429
+
430
+ else:
431
+ self.on_unknown_notification(context, msg, details)