From 55c59a4607dda133d34f1daaacf3f4930f2ee0f4 Mon Sep 17 00:00:00 2001 From: MistEO Date: Mon, 25 Mar 2024 17:54:10 +0800 Subject: [PATCH] feat: add set_option to python api --- source/binding/Python/maa/controller.py | 54 +++++++- source/binding/Python/maa/define.py | 51 ++++++++ source/binding/Python/maa/library.py | 165 +++++++++++++++++++++--- source/binding/Python/maa/library.pyi | 6 + 4 files changed, 256 insertions(+), 20 deletions(-) diff --git a/source/binding/Python/maa/controller.py b/source/binding/Python/maa/controller.py index d201fe5cf..832ec8143 100644 --- a/source/binding/Python/maa/controller.py +++ b/source/binding/Python/maa/controller.py @@ -76,7 +76,7 @@ def connected(self) -> bool: async def screencap(self) -> Optional[numpy.ndarray]: """ - screencap. + Async get the screencap of the controller. :return: image """ @@ -92,16 +92,68 @@ async def screencap(self) -> Optional[numpy.ndarray]: return image_buffer.get() def post_screencap(self) -> Future: + """ + Post a screencap to the controller. (get screencap in backgroud) + + :return: The screencap ID. + """ + maaid = Library.framework.MaaControllerPostScreencap(self._handle) return Future(maaid, self._status) async def click(self, x: int, y: int) -> bool: + """ + Async click on the controller. + + :param x: The x coordinate. + :param y: The y coordinate. + :return: True if the click was successful, False otherwise. + """ + return await self.post_click(x, y).wait() def post_click(self, x: int, y: int) -> Future: + """ + Post a click to the controller. (click in backgroud) + + :param x: The x coordinate. + :param y: The y coordinate. + :return: The click ID. + """ maaid = Library.framework.MaaControllerPostClick(self._handle, x, y) return Future(maaid, self._status) + def set_screenshot_target_long_side(self, long_side: int) -> "Controller": + """ + Set the screenshot target long side. + + :param long_side: The long side of the screenshot. + """ + + cint = ctypes.c_int32(long_side) + Library.framework.MaaControllerSetOption( + self._handle, + MaaCtrlOptionEnum.ScreenshotTargetLongSide, + ctypes.pointer(cint), + ctypes.sizeof(ctypes.c_int32), + ) + return self + + def set_screenshot_target_short_side(self, short_side: int) -> "Controller": + """ + Set the screenshot target short side. + + :param short_side: The short side of the screenshot. + """ + cint = ctypes.c_int32(short_side) + Library.framework.MaaControllerSetOption( + self._handle, + MaaCtrlOptionEnum.ScreenshotTargetShortSide, + ctypes.pointer(cint), + ctypes.sizeof(ctypes.c_int32), + ) + return self + def _status(self, maaid: int) -> MaaStatus: return Library.framework.MaaControllerStatus(self._handle, maaid) diff --git a/source/binding/Python/maa/define.py b/source/binding/Python/maa/define.py index 5d7945044..7c4e86b1e 100644 --- a/source/binding/Python/maa/define.py +++ b/source/binding/Python/maa/define.py @@ -22,13 +22,64 @@ class MaaStatusEnum(Enum): failure = 4000 +MaaLoggingLevel = ctypes.c_int32 + + +class MaaLoggingLevelEunm: + Off: MaaLoggingLevel = 0 + Fatal: MaaLoggingLevel = 1 + Error: MaaLoggingLevel = 2 + Warn: MaaLoggingLevel = 3 + Info: MaaLoggingLevel = 4 + Debug: MaaLoggingLevel = 5 + Trace: MaaLoggingLevel = 6 + All: MaaLoggingLevel = 7 + + MaaOptionValueSize = ctypes.c_uint64 MaaOptionValue = ctypes.c_void_p MaaOption = ctypes.c_int32 +MaaGlobalOption = MaaOption MaaCtrlOption = MaaOption +class MaaGlobalOptionEnum: + Invalid: MaaGlobalOption = 0 + + # Log dir + # + # value: string, eg: "C:\\Users\\Administrator\\Desktop\\log"; val_size: string length + LogDir: MaaGlobalOption = 1 + + # Whether to save draw + # + # value: bool, eg: true; val_size: sizeof(bool) + SaveDraw: MaaGlobalOption = 2 + + # Dump all screenshots and actions + # + # Recording will evaluate to true if any of this or MaaCtrlOptionEnum::MaaCtrlOption_Recording + # is true. value: bool, eg: true; val_size: sizeof(bool) + Recording: MaaGlobalOption = 3 + + # The level of log output to stdout + # + # value: MaaLoggingLevel, val_size: sizeof(MaaLoggingLevel) + # default value is MaaLoggingLevel_Error + StdoutLevel: MaaGlobalOption = 4 + + # Whether to show hit draw + # + # value: bool, eg: true; val_size: sizeof(bool) + ShowHitDraw: MaaGlobalOption = 5 + + # Whether to callback debug message + # + # value: bool, eg: true; val_size: sizeof(bool) + DebugMessage: MaaGlobalOption = 6 + + class MaaCtrlOptionEnum: Invalid: MaaCtrlOption = 0 diff --git a/source/binding/Python/maa/library.py b/source/binding/Python/maa/library.py index 84331e745..c09dcce2e 100644 --- a/source/binding/Python/maa/library.py +++ b/source/binding/Python/maa/library.py @@ -5,14 +5,12 @@ import platform from typing import Union, Optional -from .define import MaaStringView +from .define import * class Library: @classmethod - def open( - cls, path: Union[pathlib.Path, str], toolkit: bool = True - ) -> Optional[str]: + def open(cls, path: Union[pathlib.Path, str]) -> Optional[str]: """ Open the library at the given path. @@ -42,23 +40,18 @@ def open( cls.framework_libpath = ctypes.util.find_library("MaaFramework") cls.framework = lib_import(str(cls.framework_libpath)) - if not cls.framework: + try: + cls.toolkit_libpath = pathlib.Path(path) / platform_values[platform_type][1] + cls.toolkit = lib_import(str(cls.toolkit_libpath)) + except OSError: + cls.toolkit_libpath = ctypes.util.find_library("MaaToolkit") + cls.toolkit = lib_import(str(cls.toolkit_libpath)) + + if not cls.framework or not cls.toolkit: cls.initialized = False return None - if toolkit: - try: - cls.toolkit_libpath = ( - pathlib.Path(path) / platform_values[platform_type][1] - ) - cls.toolkit = lib_import(str(cls.toolkit_libpath)) - except OSError: - cls.toolkit_libpath = ctypes.util.find_library("MaaToolkit") - cls.toolkit = lib_import(str(cls.toolkit_libpath)) - else: - cls.toolkit = None - cls.toolkit_libpath = None - + cls._set_api_properties() cls.initialized = True return cls.version() @@ -76,7 +69,141 @@ def version(cls) -> str: "Library not initialized, please call `library.open()` first." ) + return cls.framework.MaaVersion().decode("utf-8") + + @classmethod + def set_log_dir(cls, path: Union[pathlib.Path, str]) -> "Library": + """ + Set the log directory. + + :param path: The path to the log directory. + """ + + if not cls.initialized: + raise RuntimeError( + "Library not initialized, please call `library.open()` first." + ) + + cls.framework.MaaSetGlobalOption( + MaaGlobalOptionEnum.LogDir, + str(path).encode("utf-8"), + len(path), + ) + return cls + + @classmethod + def set_save_draw(cls, save_draw: bool) -> "Library": + """ + Set whether to save draw. + + :param save_draw: Whether to save draw. + """ + + if not cls.initialized: + raise RuntimeError( + "Library not initialized, please call `library.open()` first." + ) + + cbool = ctypes.c_bool(save_draw) + cls.framework.MaaSetGlobalOption( + MaaGlobalOptionEnum.SaveDraw, + ctypes.pointer(cbool), + ctypes.sizeof(ctypes.c_bool), + ) + return cls + + @classmethod + def set_recording(cls, recording: bool) -> "Library": + """ + Set whether to dump all screenshots and actions. + + :param recording: Whether to dump all screenshots and actions. + """ + + if not cls.initialized: + raise RuntimeError( + "Library not initialized, please call `library.open()` first." + ) + + cbool = ctypes.c_bool(recording) + cls.framework.MaaSetGlobalOption( + MaaGlobalOptionEnum.Recording, + ctypes.pointer(cbool), + ctypes.sizeof(ctypes.c_bool), + ) + return cls + + @classmethod + def set_stdout_level(cls, level: MaaLoggingLevelEunm) -> "Library": + """ + Set the level of log output to stdout. + + :param level: The level of log output to stdout. + """ + + if not cls.initialized: + raise RuntimeError( + "Library not initialized, please call `library.open()` first." + ) + + cbool = ctypes.c_bool(level) + cls.framework.MaaSetGlobalOption( + MaaGlobalOptionEnum.StdoutLevel, + ctypes.pointer(cbool), + ctypes.sizeof(MaaLoggingLevel), + ) + return cls + + @classmethod + def set_show_hit_draw(cls, show_hit_draw: bool) -> "Library": + """ + Set whether to show hit draw. + + :param show_hit_draw: Whether to show hit draw. + """ + + if not cls.initialized: + raise RuntimeError( + "Library not initialized, please call `library.open()` first." + ) + + cbool = ctypes.c_bool(show_hit_draw) + cls.framework.MaaSetGlobalOption( + MaaGlobalOptionEnum.ShowHitDraw, + ctypes.pointer(cbool), + ctypes.sizeof(ctypes.c_bool), + ) + return cls + + @classmethod + def set_debug_message(cls, debug_message: bool) -> "Library": + """ + Set whether to callback debug message. + + :param debug_message: Whether to callback debug message. + """ + + if not cls.initialized: + raise RuntimeError( + "Library not initialized, please call `library.open()` first." + ) + + cbool = ctypes.c_bool(debug_message) + cls.framework.MaaSetGlobalOption( + MaaGlobalOptionEnum.DebugMessage, + ctypes.pointer(cbool), + ctypes.sizeof(ctypes.c_bool), + ) + return cls + + @classmethod + def _set_api_properties(cls): cls.framework.MaaVersion.restype = MaaStringView cls.framework.MaaVersion.argtypes = None - return cls.framework.MaaVersion().decode("utf-8") + cls.framework.MaaSetGlobalOption.restype = MaaBool + cls.framework.MaaSetGlobalOption.argtypes = [ + MaaGlobalOption, + MaaOptionValue, + MaaOptionValueSize, + ] diff --git a/source/binding/Python/maa/library.pyi b/source/binding/Python/maa/library.pyi index d785f64f2..59cc7321a 100644 --- a/source/binding/Python/maa/library.pyi +++ b/source/binding/Python/maa/library.pyi @@ -8,6 +8,12 @@ class _Framework: # library.py @staticmethod def MaaVersion() -> MaaStringView: ... + @staticmethod + def MaaSetGlobalOption( + key: MaaGlobalOption, + value: MaaOptionValue, + val_size: MaaOptionValueSize, + ) -> MaaBool: ... # buffer.py # StringBuffer