From 3dc24d56e1732e78bda671df367f05c4ca6963f2 Mon Sep 17 00:00:00 2001 From: YoursFunny Date: Mon, 6 Jul 2026 17:10:40 +0800 Subject: [PATCH] feat: support MuMuPlayer12 5.0 --- module/base/button.py | 33 ++++++++++++++----- module/device/method/nemu_ipc.py | 38 ++++++++++++++-------- module/device/platform/emulator_windows.py | 9 +++-- module/device/platform/platform_windows.py | 1 + 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/module/base/button.py b/module/base/button.py index 0e24bd2..171559e 100644 --- a/module/base/button.py +++ b/module/base/button.py @@ -29,8 +29,27 @@ class Button(Resource): def button(self): return area_offset(self._button, self._button_offset) - def load_offset(self, button): - self._button_offset = button._button_offset + def load_offset(self, offset): + """ + Args: + offset (Button | ButtonWrapper | tuple[int, int]): + """ + if isinstance(offset, ButtonWrapper): + offset = offset.matched_button._button_offset + elif isinstance(offset, Button): + offset = offset._button_offset + self._button_offset = offset + + def load_search(self, search): + """ + Args: + search (Button | ButtonWrapper | tuple[int, int]): + """ + if isinstance(search, ButtonWrapper): + search = search.search + elif isinstance(search, Button): + search = search.search + self.search = search def clear_offset(self): self._button_offset = (0, 0) @@ -338,10 +357,8 @@ class ButtonWrapper(Resource): Load offset from another button. Args: - button (Button, ButtonWrapper): + button (Button | ButtonWrapper | tuple[int, int]): """ - if isinstance(button, ButtonWrapper): - button = button.matched_button for b in self.iter_buttons(): b.load_offset(button) @@ -360,16 +377,16 @@ class ButtonWrapper(Resource): """ return self.matched_button.is_offset_in(x=x, y=y) - def load_search(self, area): + def load_search(self, search): """ Set `search` attribute. Note that this method is irreversible. Args: - area: + search (Button | ButtonWrapper | tuple[int, int, int, int]): """ for b in self.iter_buttons(): - b.search = area + b.load_search(search) def set_search_offset(self, offset): """ diff --git a/module/device/method/nemu_ipc.py b/module/device/method/nemu_ipc.py index a57e607..c8c4eba 100644 --- a/module/device/method/nemu_ipc.py +++ b/module/device/method/nemu_ipc.py @@ -219,7 +219,30 @@ class NemuIpcImpl: self.instance_id: int = instance_id self.display_id: int = display_id - ipc_dll = os.path.abspath(os.path.join(nemu_folder, './shell/sdk/external_renderer_ipc.dll')) + # try to load dll from various path + list_dll = [ + # MuMuPlayer12 + os.path.abspath(os.path.join(nemu_folder, './shell/sdk/external_renderer_ipc.dll')), + # MuMuPlayer12 5.0 + os.path.abspath(os.path.join(nemu_folder, './nx_device/12.0/shell/sdk/external_renderer_ipc.dll')), + ] + ipc_dll = '' + for ipc_dll in list_dll: + if not os.path.exists(ipc_dll): + continue + try: + self.lib = ctypes.CDLL(ipc_dll) + break + except OSError as e: + logger.error(e) + logger.error(f'ipc_dll={ipc_dll} exists, but cannot be loaded') + continue + if not ipc_dll: + # not found + raise NemuIpcIncompatible( + f'NemuIpc requires MuMu12 version >= 3.8.13, please check your version. ' + f'None of the following path exists: {list_dll}') + # success logger.info( f'NemuIpcImpl init, ' f'nemu_folder={nemu_folder}, ' @@ -227,19 +250,6 @@ class NemuIpcImpl: f'instance_id={instance_id}, ' f'display_id={display_id}' ) - - try: - self.lib = ctypes.CDLL(ipc_dll) - except OSError as e: - logger.error(e) - # OSError: [WinError 126] 找不到指定的模块。 - if not os.path.exists(ipc_dll): - raise NemuIpcIncompatible( - f'ipc_dll={ipc_dll} does not exist, ' - f'NemuIpc requires MuMu12 version >= 3.8.13, please check your version') - else: - raise NemuIpcIncompatible( - f'ipc_dll={ipc_dll} exists, but cannot be loaded') self.connect_id: int = 0 self.width = 0 self.height = 0 diff --git a/module/device/platform/emulator_windows.py b/module/device/platform/emulator_windows.py index 07a9f05..e91a55d 100644 --- a/module/device/platform/emulator_windows.py +++ b/module/device/platform/emulator_windows.py @@ -119,7 +119,7 @@ class Emulator(EmulatorBase): return cls.MuMuPlayerX else: return cls.MuMuPlayer - if exe == 'mumuplayer.exe': + if exe in ['mumuplayer.exe', 'mumunxmain.exe']: return cls.MuMuPlayer12 if exe == 'memu.exe': return cls.MEmuPlayer @@ -168,6 +168,9 @@ class Emulator(EmulatorBase): """ if 'MuMuPlayer.exe' in exe: return exe.replace('MuMuPlayer.exe', 'MuMuManager.exe') + # MuMuPlayer12 5.0 + elif 'MuMuNxMain.exe' in exe: + return exe.replace('MuMuNxMain.exe', 'MuMuManager.exe') elif 'LDPlayer.exe' in exe: return exe.replace('LDPlayer.exe', 'ldconsole.exe') elif 'dnplayer.exe' in exe: @@ -461,7 +464,9 @@ class EmulatorManager(EmulatorManagerBase): 'leidian9', 'Nemu', 'Nemu9', - 'MuMuPlayer-12.0' + 'MuMuPlayer', + 'MuMuPlayer-12.0', + 'MuMu Player 12.0', 'MEmu', ] for path in known_uninstall_registry_path: diff --git a/module/device/platform/platform_windows.py b/module/device/platform/platform_windows.py index 64bdad0..fded716 100644 --- a/module/device/platform/platform_windows.py +++ b/module/device/platform/platform_windows.py @@ -97,6 +97,7 @@ class PlatformWindows(PlatformBase, EmulatorManager): self.execute(f'"{exe}" -m {instance.name}') elif instance == Emulator.MuMuPlayer12: # MuMuPlayer.exe -v 0 + # MuMuNxMain.exe -v 0 if instance.MuMuPlayer12_id is None: logger.warning(f'Cannot get MuMu instance index from name {instance.name}') self.execute(f'"{exe}" -v {instance.MuMuPlayer12_id}')