mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-25 18:05:26 +00:00
Sync: [ALAS] Emulator manager
This commit is contained in:
parent
01116336f8
commit
96aa273f9b
@ -36,6 +36,21 @@ def get_serial_pair(serial):
|
||||
return None, None
|
||||
|
||||
|
||||
def remove_duplicated_path(paths):
|
||||
"""
|
||||
Args:
|
||||
paths (list[str]):
|
||||
|
||||
Returns:
|
||||
list[str]:
|
||||
"""
|
||||
paths = sorted(set(paths))
|
||||
dic = {}
|
||||
for path in paths:
|
||||
dic.setdefault(path.lower(), path)
|
||||
return list(dic.values())
|
||||
|
||||
|
||||
@dataclass
|
||||
class EmulatorInstanceBase:
|
||||
# Serial for adb connection
|
||||
@ -205,6 +220,14 @@ class EmulatorBase:
|
||||
|
||||
|
||||
class EmulatorManagerBase:
|
||||
@staticmethod
|
||||
def iter_running_emulator():
|
||||
"""
|
||||
Yields:
|
||||
str: Path to emulator executables, may contains duplicate values
|
||||
"""
|
||||
return
|
||||
|
||||
@cached_property
|
||||
def all_emulators(self) -> t.List[EmulatorBase]:
|
||||
"""
|
||||
|
@ -8,7 +8,8 @@ from dataclasses import dataclass
|
||||
# module/device/platform/emulator_base.py
|
||||
# module/device/platform/emulator_windows.py
|
||||
# Will be used in Alas Easy Install, they shouldn't import any Alas modules.
|
||||
from module.device.platform.emulator_base import EmulatorBase, EmulatorInstanceBase, EmulatorManagerBase
|
||||
from module.device.platform.emulator_base import EmulatorBase, EmulatorInstanceBase, EmulatorManagerBase, \
|
||||
remove_duplicated_path
|
||||
from module.device.platform.utils import cached_property, iter_folder
|
||||
|
||||
|
||||
@ -70,7 +71,7 @@ class Emulator(EmulatorBase):
|
||||
def path_to_type(cls, path: str) -> str:
|
||||
"""
|
||||
Args:
|
||||
path: Path to .exe file
|
||||
path: Path to .exe file, case insensitive
|
||||
|
||||
Returns:
|
||||
str: Emulator type, such as Emulator.NoxPlayer
|
||||
@ -78,46 +79,49 @@ class Emulator(EmulatorBase):
|
||||
folder, exe = os.path.split(path)
|
||||
folder, dir1 = os.path.split(folder)
|
||||
folder, dir2 = os.path.split(folder)
|
||||
if exe == 'Nox.exe':
|
||||
if dir2 == 'Nox':
|
||||
exe = exe.lower()
|
||||
dir1 = dir1.lower()
|
||||
dir2 = dir2.lower()
|
||||
if exe == 'nox.exe':
|
||||
if dir2 == 'nox':
|
||||
return cls.NoxPlayer
|
||||
elif dir2 == 'Nox64':
|
||||
elif dir2 == 'nox64':
|
||||
return cls.NoxPlayer64
|
||||
else:
|
||||
return cls.NoxPlayer
|
||||
if exe == 'Bluestacks.exe':
|
||||
if dir1 in ['BlueStacks', 'BlueStacks_cn']:
|
||||
if exe == 'bluestacks.exe':
|
||||
if dir1 in ['bluestacks', 'bluestacks_cn']:
|
||||
return cls.BlueStacks4
|
||||
elif dir1 in ['BlueStacks_nxt', 'BlueStacks_nxt_cn']:
|
||||
elif dir1 in ['bluestacks_nxt', 'bluestacks_nxt_cn']:
|
||||
return cls.BlueStacks5
|
||||
else:
|
||||
return cls.BlueStacks4
|
||||
if exe == 'HD-Player.exe':
|
||||
if dir1 in ['BlueStacks', 'BlueStacks_cn']:
|
||||
if exe == 'hd-player.exe':
|
||||
if dir1 in ['bluestacks', 'bluestacks_cn']:
|
||||
return cls.BlueStacks4
|
||||
elif dir1 in ['BlueStacks_nxt', 'BlueStacks_nxt_cn']:
|
||||
elif dir1 in ['bluestacks_nxt', 'bluestacks_nxt_cn']:
|
||||
return cls.BlueStacks5
|
||||
else:
|
||||
return cls.BlueStacks5
|
||||
if exe == 'dnplayer.exe':
|
||||
if dir1 == 'LDPlayer':
|
||||
if dir1 == 'ldplayer':
|
||||
return cls.LDPlayer3
|
||||
elif dir1 == 'LDPlayer4':
|
||||
elif dir1 == 'ldplayer4':
|
||||
return cls.LDPlayer4
|
||||
elif dir1 == 'LDPlayer9':
|
||||
elif dir1 == 'ldplayer9':
|
||||
return cls.LDPlayer9
|
||||
else:
|
||||
return cls.LDPlayer3
|
||||
if exe == 'NemuPlayer.exe':
|
||||
if exe == 'nemuplayer.exe':
|
||||
if dir2 == 'nemu':
|
||||
return cls.MuMuPlayer
|
||||
elif dir2 == 'nemu9':
|
||||
return cls.MuMuPlayerX
|
||||
else:
|
||||
return cls.MuMuPlayer
|
||||
if exe == 'MuMuPlayer.exe':
|
||||
if exe == 'mumuplayer.exe':
|
||||
return cls.MuMuPlayer12
|
||||
if exe == 'MEmu.exe':
|
||||
if exe == 'memu.exe':
|
||||
return cls.MEmuPlayer
|
||||
|
||||
return ''
|
||||
@ -143,7 +147,9 @@ class Emulator(EmulatorBase):
|
||||
elif 'NemuMultiPlayer.exe' in exe:
|
||||
yield exe.replace('NemuMultiPlayer.exe', 'NemuPlayer.exe')
|
||||
elif 'MuMuMultiPlayer.exe' in exe:
|
||||
yield exe.replace('MuMuMultiPlayer.exe', 'MuMuManager.exe')
|
||||
yield exe.replace('MuMuMultiPlayer.exe', 'MuMuPlayer.exe')
|
||||
elif 'MuMuManager.exe' in exe:
|
||||
yield exe.replace('MuMuManager.exe', 'MuMuPlayer.exe')
|
||||
elif 'MEmuConsole.exe' in exe:
|
||||
yield exe.replace('MEmuConsole.exe', 'MEmu.exe')
|
||||
else:
|
||||
@ -316,7 +322,7 @@ class EmulatorManager(EmulatorManagerBase):
|
||||
Get recently executed programs in UserAssist
|
||||
https://github.com/forensicmatt/MonitorUserAssist
|
||||
|
||||
Returns:
|
||||
Yields:
|
||||
str: Path to emulator executables, may contains duplicate values
|
||||
"""
|
||||
path = r'Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist'
|
||||
@ -447,6 +453,31 @@ class EmulatorManager(EmulatorManagerBase):
|
||||
uninstall = res.group(1) if res else uninstall
|
||||
yield uninstall
|
||||
|
||||
@staticmethod
|
||||
def iter_running_emulator():
|
||||
"""
|
||||
Yields:
|
||||
str: Path to emulator executables, may contains duplicate values
|
||||
"""
|
||||
try:
|
||||
import psutil
|
||||
except ModuleNotFoundError:
|
||||
return
|
||||
# Since this is a one-time-usage, we access psutil._psplatform.Process directly
|
||||
# to bypass the call of psutil.Process.is_running().
|
||||
# This only costs about 0.017s.
|
||||
for pid in psutil.pids():
|
||||
proc = psutil._psplatform.Process(pid)
|
||||
try:
|
||||
exe = proc.cmdline()
|
||||
exe = exe[0].replace(r'\\', '/').replace('\\', '/')
|
||||
except (psutil.AccessDenied, IndexError):
|
||||
# psutil.AccessDenied
|
||||
continue
|
||||
|
||||
if Emulator.is_emulator(exe):
|
||||
yield exe
|
||||
|
||||
@cached_property
|
||||
def all_emulators(self) -> t.List[Emulator]:
|
||||
"""
|
||||
@ -474,7 +505,7 @@ class EmulatorManager(EmulatorManagerBase):
|
||||
exe.add(ld)
|
||||
|
||||
# Uninstall registry
|
||||
for uninstall in self.iter_uninstall_registry():
|
||||
for uninstall in EmulatorManager.iter_uninstall_registry():
|
||||
# Find emulator executable from uninstaller
|
||||
for file in iter_folder(abspath(os.path.dirname(uninstall)), ext='.exe'):
|
||||
if Emulator.is_emulator(file) and os.path.exists(file):
|
||||
@ -488,9 +519,14 @@ class EmulatorManager(EmulatorManagerBase):
|
||||
if Emulator.is_emulator(file) and os.path.exists(file):
|
||||
exe.add(file)
|
||||
|
||||
# Running
|
||||
for file in EmulatorManager.iter_running_emulator():
|
||||
if os.path.exists(file):
|
||||
exe.add(file)
|
||||
|
||||
# De-redundancy
|
||||
exe = [Emulator(path).path for path in exe if Emulator.is_emulator(path)]
|
||||
exe = sorted(set(exe))
|
||||
exe = [Emulator(path) for path in exe]
|
||||
exe = [Emulator(path) for path in remove_duplicated_path(exe)]
|
||||
return exe
|
||||
|
||||
@cached_property
|
||||
|
@ -6,7 +6,8 @@ from pydantic import BaseModel
|
||||
from module.base.decorator import cached_property, del_cached_property
|
||||
from module.base.utils import SelectedGrids
|
||||
from module.device.connection import Connection
|
||||
from module.device.platform.emulator_base import EmulatorInstanceBase, EmulatorManagerBase
|
||||
from module.device.method.utils import get_serial_pair
|
||||
from module.device.platform.emulator_base import EmulatorInstanceBase, EmulatorManagerBase, remove_duplicated_path
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
@ -47,8 +48,20 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
||||
@cached_property
|
||||
def emulator_info(self) -> EmulatorInfo:
|
||||
emulator = self.config.EmulatorInfo_Emulator
|
||||
name = str(self.config.EmulatorInfo_name).strip().replace('\n', '')
|
||||
path = str(self.config.EmulatorInfo_path).strip().replace('\n', '')
|
||||
if emulator == 'auto':
|
||||
emulator = ''
|
||||
|
||||
def parse_info(value):
|
||||
if isinstance(value, str):
|
||||
value = value.strip().replace('\n', '')
|
||||
if value in ['None', 'False', 'True']:
|
||||
value = ''
|
||||
return value
|
||||
else:
|
||||
return ''
|
||||
|
||||
name = parse_info(self.config.EmulatorInfo_name)
|
||||
path = parse_info(self.config.EmulatorInfo_path)
|
||||
|
||||
return EmulatorInfo(
|
||||
emulator=emulator,
|
||||
@ -68,8 +81,14 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
||||
path=data.path,
|
||||
name=data.name,
|
||||
)
|
||||
# Redirect emulator-5554 to 127.0.0.1:5555
|
||||
serial = self.serial
|
||||
port_serial, _ = get_serial_pair(self.serial)
|
||||
if port_serial is not None:
|
||||
serial = port_serial
|
||||
|
||||
instance = self.find_emulator_instance(
|
||||
serial=str(self.config.Emulator_Serial).strip(),
|
||||
serial=serial,
|
||||
name=data.name,
|
||||
path=data.path,
|
||||
emulator=data.emulator,
|
||||
@ -117,7 +136,7 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
||||
# Search by serial
|
||||
select = instances.select(**search_args)
|
||||
if select.count == 0:
|
||||
logger.warning(f'No emulator instance with {search_args}')
|
||||
logger.warning(f'No emulator instance with {search_args}, serial invalid')
|
||||
return None
|
||||
if select.count == 1:
|
||||
instance = select[0]
|
||||
@ -130,9 +149,9 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
||||
search_args['name'] = name
|
||||
select = instances.select(**search_args)
|
||||
if select.count == 0:
|
||||
logger.warning(f'No emulator instances with {search_args}')
|
||||
return None
|
||||
if select.count == 1:
|
||||
logger.warning(f'No emulator instances with {search_args}, name invalid')
|
||||
search_args.pop('name')
|
||||
elif select.count == 1:
|
||||
instance = select[0]
|
||||
logger.hr('Emulator instance', level=2)
|
||||
logger.info(f'Found emulator instance: {instance}')
|
||||
@ -143,9 +162,9 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
||||
search_args['path'] = path
|
||||
select = instances.select(**search_args)
|
||||
if select.count == 0:
|
||||
logger.warning(f'No emulator instances with {search_args}')
|
||||
return None
|
||||
if select.count == 1:
|
||||
logger.warning(f'No emulator instances with {search_args}, path invalid')
|
||||
search_args.pop('path')
|
||||
elif select.count == 1:
|
||||
instance = select[0]
|
||||
logger.hr('Emulator instance', level=2)
|
||||
logger.info(f'Found emulator instance: {instance}')
|
||||
@ -156,9 +175,28 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
||||
search_args['type'] = emulator
|
||||
select = instances.select(**search_args)
|
||||
if select.count == 0:
|
||||
logger.warning(f'No emulator instances with {search_args}')
|
||||
return None
|
||||
if select.count == 1:
|
||||
logger.warning(f'No emulator instances with {search_args}, type invalid')
|
||||
search_args.pop('type')
|
||||
elif select.count == 1:
|
||||
instance = select[0]
|
||||
logger.hr('Emulator instance', level=2)
|
||||
logger.info(f'Found emulator instance: {instance}')
|
||||
return instance
|
||||
|
||||
# Still too many instances, search from running emulators
|
||||
running = remove_duplicated_path(list(self.iter_running_emulator()))
|
||||
logger.info('Running emulators')
|
||||
for exe in running:
|
||||
logger.info(exe)
|
||||
if len(running) == 1:
|
||||
logger.info('Only one running emulator')
|
||||
# Same as searching path
|
||||
search_args['path'] = running[0]
|
||||
select = instances.select(**search_args)
|
||||
if select.count == 0:
|
||||
logger.warning(f'No emulator instances with {search_args}, path invalid')
|
||||
search_args.pop('path')
|
||||
elif select.count == 1:
|
||||
instance = select[0]
|
||||
logger.hr('Emulator instance', level=2)
|
||||
logger.info(f'Found emulator instance: {instance}')
|
||||
@ -167,9 +205,3 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
||||
# Still too many instances
|
||||
logger.warning(f'Found multiple emulator instances with {search_args}')
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
self = PlatformBase('alas')
|
||||
d = self.emulator_instance
|
||||
print(d)
|
||||
|
Loading…
Reference in New Issue
Block a user