MaaFw 4.5.5__py3-none-macosx_13_0_arm64.whl → 5.0.0a1__py3-none-macosx_13_0_arm64.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.

Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
maa/bin/libMaaUtils.dylib CHANGED
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
 
@@ -43,7 +45,10 @@ class Context:
43
45
  return self.tasker.get_task_detail(task_id)
44
46
 
45
47
  def run_recognition(
46
- self, entry: str, image: numpy.ndarray, pipeline_override: Dict = {}
48
+ self,
49
+ entry: str,
50
+ image: numpy.ndarray,
51
+ pipeline_override: Dict = {},
47
52
  ) -> Optional[RecognitionDetail]:
48
53
  image_buffer = ImageBuffer()
49
54
  image_buffer.set(image)
@@ -84,10 +89,12 @@ class Context:
84
89
  return self.tasker.get_node_detail(node_id)
85
90
 
86
91
  def override_pipeline(self, pipeline_override: Dict) -> bool:
92
+ pipeline_json = json.dumps(pipeline_override, ensure_ascii=False)
93
+
87
94
  return bool(
88
95
  Library.framework().MaaContextOverridePipeline(
89
96
  self._handle,
90
- json.dumps(pipeline_override, ensure_ascii=False).encode(),
97
+ pipeline_json.encode(),
91
98
  )
92
99
  )
93
100
 
@@ -101,7 +108,7 @@ class Context:
101
108
  )
102
109
  )
103
110
 
104
- def get_node_data(self, name: str) -> Optional[dict]:
111
+ def get_node_data(self, name: str) -> Optional[Dict]:
105
112
  string_buffer = StringBuffer()
106
113
  if not Library.framework().MaaContextGetNodeData(
107
114
  self._handle, name.encode(), string_buffer._handle
@@ -117,6 +124,14 @@ class Context:
117
124
  except json.JSONDecodeError:
118
125
  return None
119
126
 
127
+ def get_node_object(self, name: str) -> Optional[JPipelineData]:
128
+ node_data = self.get_node_data(name)
129
+
130
+ if not node_data:
131
+ return None
132
+
133
+ return JPipelineParser.parse_pipeline_data(node_data)
134
+
120
135
  @property
121
136
  def tasker(self) -> Tasker:
122
137
  return self._tasker
@@ -145,9 +160,11 @@ class Context:
145
160
 
146
161
  @staticmethod
147
162
  def _gen_post_param(entry: str, pipeline_override: Dict) -> Tuple[bytes, bytes]:
163
+ pipeline_json = json.dumps(pipeline_override, ensure_ascii=False)
164
+
148
165
  return (
149
166
  entry.encode(),
150
- json.dumps(pipeline_override, ensure_ascii=False).encode(),
167
+ pipeline_json.encode(),
151
168
  )
152
169
 
153
170
  _api_properties_initialized: bool = False
@@ -217,3 +234,82 @@ class Context:
217
234
  Library.framework().MaaContextClone.argtypes = [
218
235
  MaaContextHandle,
219
236
  ]
237
+
238
+
239
+ class ContextEventSink(EventSink):
240
+
241
+ @dataclass
242
+ class NodeNextListDetail:
243
+ task_id: int
244
+ name: str
245
+ next_list: list[str]
246
+ focus: Any
247
+
248
+ def on_node_next_list(
249
+ self,
250
+ context: "Context",
251
+ noti_type: NotificationType,
252
+ detail: NodeNextListDetail,
253
+ ):
254
+ pass
255
+
256
+ @dataclass
257
+ class NodeRecognitionDetail:
258
+ task_id: int
259
+ reco_id: int
260
+ name: str
261
+ focus: Any
262
+
263
+ def on_node_recognition(
264
+ self,
265
+ context: "Context",
266
+ noti_type: NotificationType,
267
+ detail: NodeRecognitionDetail,
268
+ ):
269
+ pass
270
+
271
+ @dataclass
272
+ class NodeActionDetail:
273
+ task_id: int
274
+ node_id: int
275
+ name: str
276
+ focus: Any
277
+
278
+ def on_node_action(
279
+ self, context: "Context", noti_type: NotificationType, detail: NodeActionDetail
280
+ ):
281
+ pass
282
+
283
+ def on_raw_notification(self, handle: ctypes.c_void_p, msg: str, details: dict):
284
+ context = Context(handle=handle)
285
+ noti_type = EventSink._notification_type(msg)
286
+
287
+ if msg.startswith("Node.NextList"):
288
+ detail = self.NodeNextListDetail(
289
+ task_id=details["task_id"],
290
+ name=details["name"],
291
+ next_list=details["list"],
292
+ focus=details["focus"],
293
+ )
294
+ self.on_node_next_list(context, noti_type, detail)
295
+
296
+ elif msg.startswith("Node.Recognition"):
297
+ detail = self.NodeRecognitionDetail(
298
+ task_id=details["task_id"],
299
+ reco_id=details["reco_id"],
300
+ name=details["name"],
301
+ focus=details["focus"],
302
+ )
303
+ self.on_node_recognition(context, noti_type, detail)
304
+
305
+ elif msg.startswith("Node.Action"):
306
+ detail = self.NodeActionDetail(
307
+ task_id=details["task_id"],
308
+ node_id=details["node_id"],
309
+ name=details["name"],
310
+ focus=details["focus"],
311
+ )
312
+ self.on_node_action(context, noti_type, detail)
313
+
314
+ else:
315
+ self.on_unknown_notification(context, msg, details)
maa/controller.py CHANGED
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
  from typing import Any, Dict, Optional, Union
7
7
 
8
8
  from .buffer import ImageBuffer, StringBuffer
9
- from .notification_handler import NotificationHandler
9
+ from .event_sink import EventSink, NotificationType
10
10
  from .define import *
11
11
  from .job import Job, JobWithResult
12
12
  from .library import Library
@@ -20,7 +20,6 @@ __all__ = [
20
20
 
21
21
 
22
22
  class Controller:
23
- _notification_handler: Optional[NotificationHandler]
24
23
  _handle: MaaControllerHandle
25
24
  _own: bool
26
25
 
@@ -173,6 +172,27 @@ class Controller:
173
172
  )
174
173
  )
175
174
 
175
+ _sink_holder: Dict[int, "ControllerEventSink"] = {}
176
+
177
+ def add_sink(self, sink: "ControllerEventSink") -> Optional[int]:
178
+ sink_id = int(
179
+ Library.framework().MaaControllerAddSink(
180
+ self._handle, *EventSink._gen_c_param(sink)
181
+ )
182
+ )
183
+ if sink_id == MaaInvalidId:
184
+ return None
185
+
186
+ self._sink_holder[sink_id] = sink
187
+ return sink_id
188
+
189
+ def remove_sink(self, sink_id: int) -> None:
190
+ Library.framework().MaaControllerRemoveSink(self._handle, sink_id)
191
+ self._sink_holder.pop(sink_id)
192
+
193
+ def clear_sinks(self) -> None:
194
+ Library.framework().MaaControllerClearSinks(self._handle)
195
+
176
196
  ### private ###
177
197
 
178
198
  def _status(self, maaid: int) -> MaaStatus:
@@ -319,6 +339,22 @@ class Controller:
319
339
  MaaStringBufferHandle,
320
340
  ]
321
341
 
342
+ Library.framework().MaaControllerAddSink.restype = MaaSinkId
343
+ Library.framework().MaaControllerAddSink.argtypes = [
344
+ MaaControllerHandle,
345
+ MaaEventCallback,
346
+ ctypes.c_void_p,
347
+ ]
348
+
349
+ Library.framework().MaaControllerRemoveSink.restype = None
350
+ Library.framework().MaaControllerRemoveSink.argtypes = [
351
+ MaaControllerHandle,
352
+ MaaSinkId,
353
+ ]
354
+
355
+ Library.framework().MaaControllerClearSinks.restype = None
356
+ Library.framework().MaaControllerClearSinks.argtypes = [MaaControllerHandle]
357
+
322
358
 
323
359
  class AdbController(Controller):
324
360
  AGENT_BINARY_PATH = os.path.join(
@@ -334,13 +370,16 @@ class AdbController(Controller):
334
370
  input_methods: int = MaaAdbInputMethodEnum.Default,
335
371
  config: Dict[str, Any] = {},
336
372
  agent_path: Union[str, Path] = AGENT_BINARY_PATH,
337
- notification_handler: Optional[NotificationHandler] = None,
373
+ notification_handler: None = None,
338
374
  ):
375
+ if notification_handler:
376
+ raise NotImplementedError(
377
+ "NotificationHandler is deprecated, use add_sink instead."
378
+ )
379
+
339
380
  super().__init__()
340
381
  self._set_adb_api_properties()
341
382
 
342
- self._notification_handler = notification_handler
343
-
344
383
  self._handle = Library.framework().MaaAdbControllerCreate(
345
384
  str(adb_path).encode(),
346
385
  address.encode(),
@@ -348,7 +387,6 @@ class AdbController(Controller):
348
387
  MaaAdbInputMethod(input_methods),
349
388
  json.dumps(config, ensure_ascii=False).encode(),
350
389
  str(agent_path).encode(),
351
- *NotificationHandler._gen_c_param(self._notification_handler)
352
390
  )
353
391
 
354
392
  if not self._handle:
@@ -364,8 +402,6 @@ class AdbController(Controller):
364
402
  MaaAdbInputMethod,
365
403
  ctypes.c_char_p,
366
404
  ctypes.c_char_p,
367
- MaaNotificationCallback,
368
- ctypes.c_void_p,
369
405
  ]
370
406
 
371
407
 
@@ -376,17 +412,20 @@ class Win32Controller(Controller):
376
412
  hWnd: Union[ctypes.c_void_p, int, None],
377
413
  screencap_method: int = MaaWin32ScreencapMethodEnum.DXGI_DesktopDup,
378
414
  input_method: int = MaaWin32InputMethodEnum.Seize,
379
- notification_handler: Optional[NotificationHandler] = None,
415
+ notification_handler: None = None,
380
416
  ):
417
+ if notification_handler:
418
+ raise NotImplementedError(
419
+ "NotificationHandler is deprecated, use add_sink instead."
420
+ )
421
+
381
422
  super().__init__()
382
423
  self._set_win32_api_properties()
383
424
 
384
- self._notification_handler = notification_handler
385
425
  self._handle = Library.framework().MaaWin32ControllerCreate(
386
426
  hWnd,
387
427
  MaaWin32ScreencapMethod(screencap_method),
388
428
  MaaWin32InputMethod(input_method),
389
- *NotificationHandler._gen_c_param(self._notification_handler)
390
429
  )
391
430
 
392
431
  if not self._handle:
@@ -398,8 +437,6 @@ class Win32Controller(Controller):
398
437
  ctypes.c_void_p,
399
438
  MaaWin32ScreencapMethod,
400
439
  MaaWin32InputMethod,
401
- MaaNotificationCallback,
402
- ctypes.c_void_p,
403
440
  ]
404
441
 
405
442
 
@@ -411,18 +448,21 @@ class DbgController(Controller):
411
448
  write_path: Union[str, Path],
412
449
  dbg_type: int,
413
450
  config: Dict[str, Any] = {},
414
- notification_handler: Optional[NotificationHandler] = None,
451
+ notification_handler: None = None,
415
452
  ):
453
+ if notification_handler:
454
+ raise NotImplementedError(
455
+ "NotificationHandler is deprecated, use add_sink instead."
456
+ )
457
+
416
458
  super().__init__()
417
459
  self._set_dbg_api_properties()
418
460
 
419
- self._notification_handler = notification_handler
420
461
  self._handle = Library.framework().MaaDbgControllerCreate(
421
462
  str(read_path).encode(),
422
463
  str(write_path).encode(),
423
464
  MaaDbgControllerType(dbg_type),
424
465
  json.dumps(config, ensure_ascii=False).encode(),
425
- *NotificationHandler._gen_c_param(self._notification_handler)
426
466
  )
427
467
 
428
468
  if not self._handle:
@@ -435,8 +475,6 @@ class DbgController(Controller):
435
475
  ctypes.c_char_p,
436
476
  MaaDbgControllerType,
437
477
  ctypes.c_char_p,
438
- MaaNotificationCallback,
439
- ctypes.c_void_p,
440
478
  ]
441
479
 
442
480
 
@@ -446,13 +484,16 @@ class CustomController(Controller):
446
484
 
447
485
  def __init__(
448
486
  self,
449
- notification_handler: Optional[NotificationHandler] = None,
487
+ notification_handler: None = None,
450
488
  ):
489
+ if notification_handler:
490
+ raise NotImplementedError(
491
+ "NotificationHandler is deprecated, use add_sink instead."
492
+ )
493
+
451
494
  super().__init__()
452
495
  self._set_custom_api_properties()
453
496
 
454
- self._notification_handler = notification_handler
455
-
456
497
  self._callbacks = MaaCustomControllerCallbacks(
457
498
  CustomController._c_connect_agent,
458
499
  CustomController._c_request_uuid_agent,
@@ -473,7 +514,6 @@ class CustomController(Controller):
473
514
  self._handle = Library.framework().MaaCustomControllerCreate(
474
515
  self.c_handle,
475
516
  self.c_arg,
476
- *NotificationHandler._gen_c_param(self._notification_handler)
477
517
  )
478
518
 
479
519
  if not self._handle:
@@ -805,6 +845,39 @@ class CustomController(Controller):
805
845
  Library.framework().MaaCustomControllerCreate.argtypes = [
806
846
  ctypes.POINTER(MaaCustomControllerCallbacks),
807
847
  ctypes.c_void_p,
808
- MaaNotificationCallback,
809
- ctypes.c_void_p,
810
848
  ]
849
+
850
+
851
+ class ControllerEventSink(EventSink):
852
+
853
+ @dataclass
854
+ class ControllerActionDetail:
855
+ ctrl_id: int
856
+ uuid: str
857
+ action: str
858
+ param: dict
859
+
860
+ def on_controller_action(
861
+ self,
862
+ controller: Controller,
863
+ noti_type: NotificationType,
864
+ detail: ControllerActionDetail,
865
+ ):
866
+ pass
867
+
868
+ def on_raw_notification(self, handle: ctypes.c_void_p, msg: str, details: dict):
869
+
870
+ controller = Controller(handle=handle)
871
+ noti_type = EventSink._notification_type(msg)
872
+
873
+ if msg.startswith("Controller.Action"):
874
+ detail = self.ControllerActionDetail(
875
+ ctrl_id=details["ctrl_id"],
876
+ uuid=details["uuid"],
877
+ action=details["action"],
878
+ param=details["param"],
879
+ )
880
+ self.on_controller_action(controller, noti_type, detail)
881
+
882
+ else:
883
+ self.on_unknown_notification(controller, msg, details)
maa/define.py CHANGED
@@ -17,6 +17,7 @@ MaaResId = MaaId
17
17
  MaaTaskId = MaaId
18
18
  MaaRecoId = MaaId
19
19
  MaaNodeId = MaaId
20
+ MaaSinkId = MaaId
20
21
  MaaInvalidId = MaaId(0)
21
22
 
22
23
  MaaStringBufferHandle = ctypes.c_void_p
@@ -240,8 +241,8 @@ class MaaDbgControllerTypeEnum(IntEnum):
240
241
 
241
242
  FUNCTYPE = ctypes.WINFUNCTYPE if (platform.system() == "Windows") else ctypes.CFUNCTYPE
242
243
 
243
- MaaNotificationCallback = FUNCTYPE(
244
- None, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p
244
+ MaaEventCallback = FUNCTYPE(
245
+ None, ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p
245
246
  )
246
247
 
247
248
  MaaCustomRecognitionCallback = FUNCTYPE(
maa/event_sink.py ADDED
@@ -0,0 +1,74 @@
1
+ import ctypes
2
+ import json
3
+ from abc import ABC
4
+ from typing import Optional, Tuple, Any
5
+ from enum import IntEnum
6
+ from dataclasses import dataclass
7
+
8
+ from .define import MaaEventCallback
9
+
10
+
11
+ # class NotificationEvent(IntEnum):
12
+ # ResourceLoading = 1
13
+ # ControllerAction = 2
14
+ # TaskerTask = 3
15
+ # TaskNextList = 4
16
+ # TaskRecognition = 5
17
+ # TaskAction = 6
18
+
19
+
20
+ class NotificationType(IntEnum):
21
+ Unknown = 0
22
+ Starting = 1
23
+ Succeeded = 2
24
+ Failed = 3
25
+
26
+
27
+ class EventSink(ABC):
28
+ def on_unknown_notification(self, instance, msg: str, details: dict):
29
+ pass
30
+
31
+ def on_raw_notification(self, handle: ctypes.c_void_p, msg: str, details: dict):
32
+ pass
33
+
34
+ @property
35
+ def c_callback(self) -> MaaEventCallback:
36
+ return self._c_sink_agent
37
+
38
+ @property
39
+ def c_callback_arg(self) -> ctypes.c_void_p:
40
+ return ctypes.c_void_p.from_buffer(ctypes.py_object(self))
41
+
42
+ @staticmethod
43
+ def _gen_c_param(
44
+ sink: "EventSink",
45
+ ) -> Tuple[MaaEventCallback, ctypes.c_void_p]:
46
+ return sink.c_callback, sink.c_callback_arg
47
+
48
+ @staticmethod
49
+ def _notification_type(message: str) -> NotificationType:
50
+ if message.endswith(".Starting"):
51
+ return NotificationType.Starting
52
+ elif message.endswith(".Succeeded"):
53
+ return NotificationType.Succeeded
54
+ elif message.endswith(".Failed"):
55
+ return NotificationType.Failed
56
+ else:
57
+ return NotificationType.Unknown
58
+
59
+ @staticmethod
60
+ @MaaEventCallback
61
+ def _c_sink_agent(
62
+ handle: ctypes.c_void_p,
63
+ msg: ctypes.c_char_p,
64
+ details_json: ctypes.c_char_p,
65
+ callback_arg: ctypes.c_void_p,
66
+ ):
67
+ if not callback_arg:
68
+ return
69
+
70
+ self: EventSink = ctypes.cast(callback_arg, ctypes.py_object).value
71
+
72
+ self.on_raw_notification(
73
+ handle, msg.decode(), json.loads(details_json.decode())
74
+ )