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
|
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
|
@dataclass
|
||||||
class EmulatorInstanceBase:
|
class EmulatorInstanceBase:
|
||||||
# Serial for adb connection
|
# Serial for adb connection
|
||||||
@ -205,6 +220,14 @@ class EmulatorBase:
|
|||||||
|
|
||||||
|
|
||||||
class EmulatorManagerBase:
|
class EmulatorManagerBase:
|
||||||
|
@staticmethod
|
||||||
|
def iter_running_emulator():
|
||||||
|
"""
|
||||||
|
Yields:
|
||||||
|
str: Path to emulator executables, may contains duplicate values
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def all_emulators(self) -> t.List[EmulatorBase]:
|
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_base.py
|
||||||
# module/device/platform/emulator_windows.py
|
# module/device/platform/emulator_windows.py
|
||||||
# Will be used in Alas Easy Install, they shouldn't import any Alas modules.
|
# 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
|
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:
|
def path_to_type(cls, path: str) -> str:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
path: Path to .exe file
|
path: Path to .exe file, case insensitive
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Emulator type, such as Emulator.NoxPlayer
|
str: Emulator type, such as Emulator.NoxPlayer
|
||||||
@ -78,46 +79,49 @@ class Emulator(EmulatorBase):
|
|||||||
folder, exe = os.path.split(path)
|
folder, exe = os.path.split(path)
|
||||||
folder, dir1 = os.path.split(folder)
|
folder, dir1 = os.path.split(folder)
|
||||||
folder, dir2 = os.path.split(folder)
|
folder, dir2 = os.path.split(folder)
|
||||||
if exe == 'Nox.exe':
|
exe = exe.lower()
|
||||||
if dir2 == 'Nox':
|
dir1 = dir1.lower()
|
||||||
|
dir2 = dir2.lower()
|
||||||
|
if exe == 'nox.exe':
|
||||||
|
if dir2 == 'nox':
|
||||||
return cls.NoxPlayer
|
return cls.NoxPlayer
|
||||||
elif dir2 == 'Nox64':
|
elif dir2 == 'nox64':
|
||||||
return cls.NoxPlayer64
|
return cls.NoxPlayer64
|
||||||
else:
|
else:
|
||||||
return cls.NoxPlayer
|
return cls.NoxPlayer
|
||||||
if exe == 'Bluestacks.exe':
|
if exe == 'bluestacks.exe':
|
||||||
if dir1 in ['BlueStacks', 'BlueStacks_cn']:
|
if dir1 in ['bluestacks', 'bluestacks_cn']:
|
||||||
return cls.BlueStacks4
|
return cls.BlueStacks4
|
||||||
elif dir1 in ['BlueStacks_nxt', 'BlueStacks_nxt_cn']:
|
elif dir1 in ['bluestacks_nxt', 'bluestacks_nxt_cn']:
|
||||||
return cls.BlueStacks5
|
return cls.BlueStacks5
|
||||||
else:
|
else:
|
||||||
return cls.BlueStacks4
|
return cls.BlueStacks4
|
||||||
if exe == 'HD-Player.exe':
|
if exe == 'hd-player.exe':
|
||||||
if dir1 in ['BlueStacks', 'BlueStacks_cn']:
|
if dir1 in ['bluestacks', 'bluestacks_cn']:
|
||||||
return cls.BlueStacks4
|
return cls.BlueStacks4
|
||||||
elif dir1 in ['BlueStacks_nxt', 'BlueStacks_nxt_cn']:
|
elif dir1 in ['bluestacks_nxt', 'bluestacks_nxt_cn']:
|
||||||
return cls.BlueStacks5
|
return cls.BlueStacks5
|
||||||
else:
|
else:
|
||||||
return cls.BlueStacks5
|
return cls.BlueStacks5
|
||||||
if exe == 'dnplayer.exe':
|
if exe == 'dnplayer.exe':
|
||||||
if dir1 == 'LDPlayer':
|
if dir1 == 'ldplayer':
|
||||||
return cls.LDPlayer3
|
return cls.LDPlayer3
|
||||||
elif dir1 == 'LDPlayer4':
|
elif dir1 == 'ldplayer4':
|
||||||
return cls.LDPlayer4
|
return cls.LDPlayer4
|
||||||
elif dir1 == 'LDPlayer9':
|
elif dir1 == 'ldplayer9':
|
||||||
return cls.LDPlayer9
|
return cls.LDPlayer9
|
||||||
else:
|
else:
|
||||||
return cls.LDPlayer3
|
return cls.LDPlayer3
|
||||||
if exe == 'NemuPlayer.exe':
|
if exe == 'nemuplayer.exe':
|
||||||
if dir2 == 'nemu':
|
if dir2 == 'nemu':
|
||||||
return cls.MuMuPlayer
|
return cls.MuMuPlayer
|
||||||
elif dir2 == 'nemu9':
|
elif dir2 == 'nemu9':
|
||||||
return cls.MuMuPlayerX
|
return cls.MuMuPlayerX
|
||||||
else:
|
else:
|
||||||
return cls.MuMuPlayer
|
return cls.MuMuPlayer
|
||||||
if exe == 'MuMuPlayer.exe':
|
if exe == 'mumuplayer.exe':
|
||||||
return cls.MuMuPlayer12
|
return cls.MuMuPlayer12
|
||||||
if exe == 'MEmu.exe':
|
if exe == 'memu.exe':
|
||||||
return cls.MEmuPlayer
|
return cls.MEmuPlayer
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
@ -143,7 +147,9 @@ class Emulator(EmulatorBase):
|
|||||||
elif 'NemuMultiPlayer.exe' in exe:
|
elif 'NemuMultiPlayer.exe' in exe:
|
||||||
yield exe.replace('NemuMultiPlayer.exe', 'NemuPlayer.exe')
|
yield exe.replace('NemuMultiPlayer.exe', 'NemuPlayer.exe')
|
||||||
elif 'MuMuMultiPlayer.exe' in 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:
|
elif 'MEmuConsole.exe' in exe:
|
||||||
yield exe.replace('MEmuConsole.exe', 'MEmu.exe')
|
yield exe.replace('MEmuConsole.exe', 'MEmu.exe')
|
||||||
else:
|
else:
|
||||||
@ -316,7 +322,7 @@ class EmulatorManager(EmulatorManagerBase):
|
|||||||
Get recently executed programs in UserAssist
|
Get recently executed programs in UserAssist
|
||||||
https://github.com/forensicmatt/MonitorUserAssist
|
https://github.com/forensicmatt/MonitorUserAssist
|
||||||
|
|
||||||
Returns:
|
Yields:
|
||||||
str: Path to emulator executables, may contains duplicate values
|
str: Path to emulator executables, may contains duplicate values
|
||||||
"""
|
"""
|
||||||
path = r'Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist'
|
path = r'Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist'
|
||||||
@ -447,6 +453,31 @@ class EmulatorManager(EmulatorManagerBase):
|
|||||||
uninstall = res.group(1) if res else uninstall
|
uninstall = res.group(1) if res else uninstall
|
||||||
yield 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
|
@cached_property
|
||||||
def all_emulators(self) -> t.List[Emulator]:
|
def all_emulators(self) -> t.List[Emulator]:
|
||||||
"""
|
"""
|
||||||
@ -474,7 +505,7 @@ class EmulatorManager(EmulatorManagerBase):
|
|||||||
exe.add(ld)
|
exe.add(ld)
|
||||||
|
|
||||||
# Uninstall registry
|
# Uninstall registry
|
||||||
for uninstall in self.iter_uninstall_registry():
|
for uninstall in EmulatorManager.iter_uninstall_registry():
|
||||||
# Find emulator executable from uninstaller
|
# Find emulator executable from uninstaller
|
||||||
for file in iter_folder(abspath(os.path.dirname(uninstall)), ext='.exe'):
|
for file in iter_folder(abspath(os.path.dirname(uninstall)), ext='.exe'):
|
||||||
if Emulator.is_emulator(file) and os.path.exists(file):
|
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):
|
if Emulator.is_emulator(file) and os.path.exists(file):
|
||||||
exe.add(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 = [Emulator(path).path for path in exe if Emulator.is_emulator(path)]
|
||||||
exe = sorted(set(exe))
|
exe = [Emulator(path) for path in remove_duplicated_path(exe)]
|
||||||
exe = [Emulator(path) for path in exe]
|
|
||||||
return exe
|
return exe
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
@ -6,7 +6,8 @@ from pydantic import BaseModel
|
|||||||
from module.base.decorator import cached_property, del_cached_property
|
from module.base.decorator import cached_property, del_cached_property
|
||||||
from module.base.utils import SelectedGrids
|
from module.base.utils import SelectedGrids
|
||||||
from module.device.connection import Connection
|
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
|
from module.logger import logger
|
||||||
|
|
||||||
|
|
||||||
@ -47,8 +48,20 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
|||||||
@cached_property
|
@cached_property
|
||||||
def emulator_info(self) -> EmulatorInfo:
|
def emulator_info(self) -> EmulatorInfo:
|
||||||
emulator = self.config.EmulatorInfo_Emulator
|
emulator = self.config.EmulatorInfo_Emulator
|
||||||
name = str(self.config.EmulatorInfo_name).strip().replace('\n', '')
|
if emulator == 'auto':
|
||||||
path = str(self.config.EmulatorInfo_path).strip().replace('\n', '')
|
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(
|
return EmulatorInfo(
|
||||||
emulator=emulator,
|
emulator=emulator,
|
||||||
@ -68,8 +81,14 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
|||||||
path=data.path,
|
path=data.path,
|
||||||
name=data.name,
|
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(
|
instance = self.find_emulator_instance(
|
||||||
serial=str(self.config.Emulator_Serial).strip(),
|
serial=serial,
|
||||||
name=data.name,
|
name=data.name,
|
||||||
path=data.path,
|
path=data.path,
|
||||||
emulator=data.emulator,
|
emulator=data.emulator,
|
||||||
@ -117,7 +136,7 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
|||||||
# Search by serial
|
# Search by serial
|
||||||
select = instances.select(**search_args)
|
select = instances.select(**search_args)
|
||||||
if select.count == 0:
|
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
|
return None
|
||||||
if select.count == 1:
|
if select.count == 1:
|
||||||
instance = select[0]
|
instance = select[0]
|
||||||
@ -130,9 +149,9 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
|||||||
search_args['name'] = name
|
search_args['name'] = name
|
||||||
select = instances.select(**search_args)
|
select = instances.select(**search_args)
|
||||||
if select.count == 0:
|
if select.count == 0:
|
||||||
logger.warning(f'No emulator instances with {search_args}')
|
logger.warning(f'No emulator instances with {search_args}, name invalid')
|
||||||
return None
|
search_args.pop('name')
|
||||||
if select.count == 1:
|
elif select.count == 1:
|
||||||
instance = select[0]
|
instance = select[0]
|
||||||
logger.hr('Emulator instance', level=2)
|
logger.hr('Emulator instance', level=2)
|
||||||
logger.info(f'Found emulator instance: {instance}')
|
logger.info(f'Found emulator instance: {instance}')
|
||||||
@ -143,9 +162,9 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
|||||||
search_args['path'] = path
|
search_args['path'] = path
|
||||||
select = instances.select(**search_args)
|
select = instances.select(**search_args)
|
||||||
if select.count == 0:
|
if select.count == 0:
|
||||||
logger.warning(f'No emulator instances with {search_args}')
|
logger.warning(f'No emulator instances with {search_args}, path invalid')
|
||||||
return None
|
search_args.pop('path')
|
||||||
if select.count == 1:
|
elif select.count == 1:
|
||||||
instance = select[0]
|
instance = select[0]
|
||||||
logger.hr('Emulator instance', level=2)
|
logger.hr('Emulator instance', level=2)
|
||||||
logger.info(f'Found emulator instance: {instance}')
|
logger.info(f'Found emulator instance: {instance}')
|
||||||
@ -156,9 +175,28 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
|||||||
search_args['type'] = emulator
|
search_args['type'] = emulator
|
||||||
select = instances.select(**search_args)
|
select = instances.select(**search_args)
|
||||||
if select.count == 0:
|
if select.count == 0:
|
||||||
logger.warning(f'No emulator instances with {search_args}')
|
logger.warning(f'No emulator instances with {search_args}, type invalid')
|
||||||
return None
|
search_args.pop('type')
|
||||||
if select.count == 1:
|
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]
|
instance = select[0]
|
||||||
logger.hr('Emulator instance', level=2)
|
logger.hr('Emulator instance', level=2)
|
||||||
logger.info(f'Found emulator instance: {instance}')
|
logger.info(f'Found emulator instance: {instance}')
|
||||||
@ -167,9 +205,3 @@ class PlatformBase(Connection, EmulatorManagerBase):
|
|||||||
# Still too many instances
|
# Still too many instances
|
||||||
logger.warning(f'Found multiple emulator instances with {search_args}')
|
logger.warning(f'Found multiple emulator instances with {search_args}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
self = PlatformBase('alas')
|
|
||||||
d = self.emulator_instance
|
|
||||||
print(d)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user