2024-01-14 18:34:26 +00:00
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
from module.base.base import ModuleBase
|
|
|
|
|
from module.base.timer import Timer
|
2024-03-16 08:05:45 +00:00
|
|
|
|
from module.base.utils import area_offset, random_rectangle_vector_opted
|
2024-01-14 18:34:26 +00:00
|
|
|
|
from module.device.method.utils import AreaButton
|
|
|
|
|
from module.exception import GameNotRunningError, RequestHumanTakeover
|
|
|
|
|
from module.logger import logger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class XPath:
|
2024-03-16 08:05:45 +00:00
|
|
|
|
"""
|
|
|
|
|
xpath 元素,元素可通过 uiautomator2 内的 weditor.exe 查找
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
登录界面元素
|
|
|
|
|
"""
|
2024-06-29 12:11:14 +00:00
|
|
|
|
# 帐号登录界面的进入游戏按钮
|
2024-01-14 18:34:26 +00:00
|
|
|
|
ACCOUNT_LOGIN = '//*[@text="进入游戏"]'
|
2024-06-29 12:11:14 +00:00
|
|
|
|
# 帐号登录界面,有这些按钮说明帐号没登录
|
|
|
|
|
ACCOUNT_PASSWORD_LOGIN = '//*[@text="账号密码"]'
|
|
|
|
|
ACCOUNT_REGISTER = '//*[@text="立即注册"]'
|
|
|
|
|
ACCOUNT_FORGET_PASSWORD = '//*[@text="忘记密码"]'
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 登录后的弹窗,获得免费时长
|
|
|
|
|
GET_REWARD = '//*[@text="点击空白区域关闭"]'
|
2024-03-27 13:43:28 +00:00
|
|
|
|
# 用户协议和隐私政策更新提示
|
|
|
|
|
# - 拒绝 - 接受
|
|
|
|
|
AGREEMENT_ACCEPT = '//*[@text="接受"]'
|
|
|
|
|
# 版本更新
|
|
|
|
|
# - 立即更新
|
|
|
|
|
UPDATE_CONFIRM = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mUpgradeDialogOK"]'
|
|
|
|
|
# 新版本已下载完成
|
|
|
|
|
# - 开始安装
|
|
|
|
|
UPDATE_INSTALL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mBtnConfirm"]'
|
|
|
|
|
# 安卓系统弹窗
|
|
|
|
|
# 要更新此应用吗?- 取消 - 更新
|
|
|
|
|
# 已完成安装应用。-完成 -打开
|
|
|
|
|
ANDROID_UPDATE_CONFIRM = '//*[@resource-id="android:id/button1"]'
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 补丁资源已更新,重启游戏可活动更好的游玩体验
|
|
|
|
|
# - 下次再说 - 关闭游戏
|
|
|
|
|
POPUP_TITLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/titleTv"]'
|
|
|
|
|
POPUP_CONFIRM = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/confirmTv"]'
|
|
|
|
|
POPUP_CANCEL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/cancelTv"]'
|
|
|
|
|
# 畅玩卡的剩余时间
|
2024-06-19 05:44:52 +00:00
|
|
|
|
REMAIN_SEASON_PASS = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvRemindTime"]'
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 星云币时长:0 分钟
|
2024-06-19 05:44:52 +00:00
|
|
|
|
REMAIN_PAID = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvCoinCount"]'
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 免费时长: 600 分钟
|
2024-06-19 05:44:52 +00:00
|
|
|
|
REMAIN_FREE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvFreeTimeCount"]'
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 主界面的开始游戏按钮
|
|
|
|
|
START_GAME = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/btnLauncher"]'
|
2024-06-19 05:44:52 +00:00
|
|
|
|
# 请选择排队队列
|
|
|
|
|
# - 星云币时长快速通道队列 - 普通队列
|
|
|
|
|
QUEUE_SELECT_TITLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvSelectQueueTypeTitle"]'
|
|
|
|
|
QUEUE_SELECT_PRIOR = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvOptionPrior"]'
|
|
|
|
|
QUEUE_SELECT_NORMAL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/clOptionNormal"]'
|
|
|
|
|
# 排队中
|
|
|
|
|
QUEUE_TITLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvEnqueueDialogTitle"]'
|
|
|
|
|
# 预计等待时间
|
|
|
|
|
QUEUE_REMAIN = ('//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/llEnqueueBody"]'
|
|
|
|
|
'//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvSingleValue"]')
|
2024-03-16 08:05:45 +00:00
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
游戏界面元素
|
|
|
|
|
"""
|
|
|
|
|
# 网络状态 简洁
|
|
|
|
|
FLOAT_STATE_SIMPLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tvSimpleNetStateMode"]'
|
|
|
|
|
# 网络状态 详细
|
|
|
|
|
FLOAT_STATE_DETAIL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_ping_value"]'
|
|
|
|
|
"""
|
|
|
|
|
悬浮窗及侧边栏元素
|
|
|
|
|
"""
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 悬浮窗
|
2024-07-31 10:54:34 +00:00
|
|
|
|
FLOAT_WINDOW = '//*[@package="com.miHoYo.cloudgames.hkrpg" and @class="android.widget.LinearLayout"]'
|
2024-05-30 04:16:25 +00:00
|
|
|
|
# 退出按钮,返回登录页面
|
|
|
|
|
FLOAT_EXIT = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/iv_exit"]'
|
2024-03-16 08:05:45 +00:00
|
|
|
|
# 弹出侧边栏的 节点信息
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 将这个区域向右偏移作为退出悬浮窗的按钮
|
2024-03-16 08:05:45 +00:00
|
|
|
|
FLOAT_DELAY = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_node_region"]'
|
|
|
|
|
# 弹出侧边栏的滚动区域
|
|
|
|
|
SCROLL_VIEW = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/innerScrollView"]'
|
|
|
|
|
# 画质选择 超高清
|
|
|
|
|
# 选中时selected=True
|
|
|
|
|
SETTING_BITRATE_UHD = '//*[@text="超高清"]'
|
|
|
|
|
# 网络状态 开关
|
|
|
|
|
SETTING_NET_STATE_TOGGLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/sw_net_state"]'
|
|
|
|
|
SETTING_NET_STATE_SIMPLE = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mTvTitleOfSimpleMode"]'
|
|
|
|
|
SETTING_NET_STATE_DETAIL = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/mTvTitleOfDetailMode"]'
|
|
|
|
|
# 问题反馈
|
|
|
|
|
SETTING_PROBLEM = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_problem"]'
|
|
|
|
|
# 下载游戏
|
|
|
|
|
SETTING_DOWNLOAD = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/tv_downloadGame"]'
|
2024-01-14 18:34:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LoginAndroidCloud(ModuleBase):
|
|
|
|
|
def _cloud_start(self, skip_first=False):
|
|
|
|
|
"""
|
|
|
|
|
Pages:
|
2024-05-30 04:16:25 +00:00
|
|
|
|
out: XPath.START_GAME
|
2024-01-14 18:34:26 +00:00
|
|
|
|
"""
|
|
|
|
|
logger.hr('Cloud start')
|
|
|
|
|
update_checker = Timer(2)
|
|
|
|
|
while 1:
|
|
|
|
|
if skip_first:
|
|
|
|
|
skip_first = False
|
|
|
|
|
else:
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
|
|
|
|
|
# End
|
|
|
|
|
if self.appear(XPath.START_GAME):
|
|
|
|
|
logger.info('Login to cloud main page')
|
|
|
|
|
break
|
2024-06-29 12:11:14 +00:00
|
|
|
|
if (
|
|
|
|
|
self.appear(XPath.ACCOUNT_REGISTER)
|
|
|
|
|
or self.appear(XPath.ACCOUNT_PASSWORD_LOGIN)
|
|
|
|
|
or self.appear(XPath.ACCOUNT_FORGET_PASSWORD)
|
|
|
|
|
):
|
2024-01-14 18:34:26 +00:00
|
|
|
|
logger.critical('Account not login, you must have login once before running')
|
|
|
|
|
raise RequestHumanTakeover
|
|
|
|
|
if update_checker.started() and update_checker.reached():
|
|
|
|
|
if not self.device.app_is_running():
|
|
|
|
|
logger.error('Detected hot fixes from game server, game died')
|
|
|
|
|
raise GameNotRunningError('Game not running')
|
|
|
|
|
update_checker.clear()
|
|
|
|
|
|
|
|
|
|
# Click
|
|
|
|
|
if self.appear_then_click(XPath.GET_REWARD):
|
|
|
|
|
continue
|
2024-06-29 12:11:14 +00:00
|
|
|
|
if self.appear_then_click(XPath.ACCOUNT_LOGIN):
|
|
|
|
|
continue
|
2024-01-14 18:34:26 +00:00
|
|
|
|
if self.appear_then_click(XPath.POPUP_CONFIRM):
|
|
|
|
|
update_checker.start()
|
|
|
|
|
continue
|
2024-03-27 13:43:28 +00:00
|
|
|
|
# Update
|
|
|
|
|
if self.appear_then_click(XPath.AGREEMENT_ACCEPT):
|
|
|
|
|
continue
|
|
|
|
|
if self.appear_then_click(XPath.UPDATE_CONFIRM):
|
|
|
|
|
continue
|
|
|
|
|
button = self.xpath(XPath.UPDATE_INSTALL)
|
|
|
|
|
if button.text == '开始安装':
|
|
|
|
|
if self.appear_then_click(button):
|
|
|
|
|
continue
|
|
|
|
|
button = self.xpath(XPath.ANDROID_UPDATE_CONFIRM)
|
|
|
|
|
if button.text in ['更新', '打开']:
|
|
|
|
|
if self.appear_then_click(button):
|
|
|
|
|
continue
|
2024-01-14 18:34:26 +00:00
|
|
|
|
|
|
|
|
|
def _cloud_get_remain(self):
|
|
|
|
|
"""
|
|
|
|
|
Pages:
|
2024-05-30 04:16:25 +00:00
|
|
|
|
in: XPath.START_GAME
|
2024-01-14 18:34:26 +00:00
|
|
|
|
"""
|
|
|
|
|
regex = re.compile(r'(\d+)')
|
|
|
|
|
|
|
|
|
|
text = self.xpath(XPath.REMAIN_SEASON_PASS).text
|
|
|
|
|
logger.info(f'Remain season pass: {text}')
|
|
|
|
|
if res := regex.search(text):
|
|
|
|
|
season_pass = int(res.group(1))
|
|
|
|
|
else:
|
|
|
|
|
season_pass = 0
|
2024-07-31 11:06:20 +00:00
|
|
|
|
# 42 天
|
|
|
|
|
# 5 小时
|
|
|
|
|
if '天' in text:
|
|
|
|
|
pass
|
|
|
|
|
elif '小时' in text:
|
|
|
|
|
season_pass = round(season_pass / 24, 2)
|
|
|
|
|
elif '分钟' in text:
|
|
|
|
|
season_pass = round(season_pass / 24 / 60, 3)
|
2024-08-01 04:46:02 +00:00
|
|
|
|
elif text == '':
|
2024-08-01 17:21:56 +00:00
|
|
|
|
season_pass = 0
|
2024-07-31 11:06:20 +00:00
|
|
|
|
else:
|
|
|
|
|
logger.error(f'Unexpected season pass text: {text}')
|
2024-01-14 18:34:26 +00:00
|
|
|
|
|
|
|
|
|
text = self.xpath(XPath.REMAIN_PAID).text
|
|
|
|
|
logger.info(f'Remain paid: {text}')
|
|
|
|
|
if res := regex.search(text):
|
|
|
|
|
paid = int(res.group(1))
|
|
|
|
|
else:
|
|
|
|
|
paid = 0
|
|
|
|
|
|
|
|
|
|
text = self.xpath(XPath.REMAIN_FREE).text
|
|
|
|
|
logger.info(f'Remain free: {text}')
|
|
|
|
|
if res := regex.search(text):
|
|
|
|
|
free = int(res.group(1))
|
|
|
|
|
else:
|
|
|
|
|
free = 0
|
|
|
|
|
|
|
|
|
|
logger.info(f'Cloud remain: season pass {season_pass} days, {paid} min paid, {free} min free')
|
|
|
|
|
with self.config.multi_set():
|
2024-06-16 18:29:39 +00:00
|
|
|
|
self.config.stored.CloudRemainSeasonPass.value = season_pass
|
|
|
|
|
self.config.stored.CloudRemainPaid.value = paid
|
|
|
|
|
self.config.stored.CloudRemainFree.value = free
|
2024-01-14 18:34:26 +00:00
|
|
|
|
|
2024-07-19 21:10:08 +00:00
|
|
|
|
def _is_cloud_ingame(self):
|
|
|
|
|
button = self.xpath(XPath.FLOAT_WINDOW)
|
|
|
|
|
if self.appear(button):
|
|
|
|
|
# Confirm float window size
|
|
|
|
|
width, height = button.size
|
|
|
|
|
if (width < 120 and height < 120) and (width / height < 0.6 or height / width < 0.6):
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
2024-01-14 18:34:26 +00:00
|
|
|
|
def _cloud_enter(self, skip_first=False):
|
|
|
|
|
"""
|
|
|
|
|
Pages:
|
2024-05-30 04:16:25 +00:00
|
|
|
|
in: XPath.START_GAME
|
2024-03-16 08:05:45 +00:00
|
|
|
|
out: page_main
|
2024-01-14 18:34:26 +00:00
|
|
|
|
"""
|
|
|
|
|
logger.hr('Cloud enter')
|
|
|
|
|
while 1:
|
|
|
|
|
if skip_first:
|
|
|
|
|
skip_first = False
|
|
|
|
|
else:
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
|
|
|
|
|
# End
|
2024-07-19 21:10:08 +00:00
|
|
|
|
if self._is_cloud_ingame():
|
|
|
|
|
logger.info('Cloud game entered')
|
|
|
|
|
break
|
2024-03-16 08:05:45 +00:00
|
|
|
|
|
|
|
|
|
# Queue daemon
|
|
|
|
|
button = self.xpath(XPath.QUEUE_REMAIN)
|
2024-06-19 05:44:52 +00:00
|
|
|
|
if self.appear(button, interval=20):
|
2024-03-16 08:05:45 +00:00
|
|
|
|
remain = button.text
|
|
|
|
|
logger.info(f'Queue remain: {remain}')
|
|
|
|
|
self.device.stuck_record_clear()
|
2024-01-14 18:34:26 +00:00
|
|
|
|
|
|
|
|
|
# Click
|
2024-03-27 13:43:28 +00:00
|
|
|
|
if self.appear_then_click(XPath.GET_REWARD):
|
|
|
|
|
continue
|
2024-01-14 18:34:26 +00:00
|
|
|
|
if self.appear_then_click(XPath.START_GAME):
|
|
|
|
|
continue
|
|
|
|
|
if self.appear(XPath.POPUP_CONFIRM, interval=5):
|
2024-03-16 08:05:45 +00:00
|
|
|
|
title = self.xpath(XPath.POPUP_TITLE).text
|
|
|
|
|
logger.info(f'Popup: {title}')
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 计费提示
|
|
|
|
|
# 本次游戏将使用畅玩卡无限畅玩
|
|
|
|
|
# - 进入游戏(9s) - 退出游戏
|
|
|
|
|
if title == '计费提示':
|
|
|
|
|
self.device.click(self.xpath(XPath.POPUP_CONFIRM))
|
|
|
|
|
continue
|
2024-03-16 08:05:45 +00:00
|
|
|
|
# 是否使用星云币时长进入游戏
|
|
|
|
|
# 使用后可优先排队进入游戏,本次游戏仅可使用星云币时长,无法消耗免费时长
|
|
|
|
|
# - 确认使用 - 暂不使用
|
|
|
|
|
if title == '是否使用星云币时长进入游戏':
|
|
|
|
|
self.device.click(self.xpath(XPath.POPUP_CONFIRM))
|
|
|
|
|
continue
|
2024-01-14 18:34:26 +00:00
|
|
|
|
# 连接中断
|
|
|
|
|
# 因为您长时间未操作游戏,已中断连接,错误码: -1022
|
|
|
|
|
# - 退出游戏
|
|
|
|
|
if title == '连接中断':
|
|
|
|
|
self.device.click(self.xpath(XPath.POPUP_CONFIRM))
|
|
|
|
|
continue
|
2024-06-19 05:44:52 +00:00
|
|
|
|
if self.appear_then_click(XPath.QUEUE_SELECT_NORMAL):
|
|
|
|
|
continue
|
2024-01-14 18:34:26 +00:00
|
|
|
|
|
2024-03-16 08:05:45 +00:00
|
|
|
|
# Disable net state display
|
|
|
|
|
if self._cloud_net_state_appear():
|
|
|
|
|
self._cloud_setting_disable_net_state()
|
|
|
|
|
# Login to game
|
|
|
|
|
from tasks.login.login import Login
|
|
|
|
|
Login(config=self.config, device=self.device).handle_app_login()
|
|
|
|
|
|
2024-01-14 18:34:26 +00:00
|
|
|
|
def _cloud_setting_enter(self, skip_first=True):
|
2024-05-30 04:16:25 +00:00
|
|
|
|
"""
|
|
|
|
|
Pages:
|
|
|
|
|
in: XPath.FLOAT_WINDOW
|
|
|
|
|
out: XPath.FLOAT_DELAY, setting aside expanded
|
|
|
|
|
"""
|
2024-01-14 18:34:26 +00:00
|
|
|
|
while 1:
|
|
|
|
|
if skip_first:
|
|
|
|
|
skip_first = False
|
|
|
|
|
else:
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
|
|
|
|
|
if self.appear(XPath.FLOAT_DELAY):
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if self.appear_then_click(XPath.FLOAT_WINDOW, interval=3):
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
def _cloud_setting_exit(self, skip_first=True):
|
2024-05-30 04:16:25 +00:00
|
|
|
|
"""
|
|
|
|
|
Pages:
|
|
|
|
|
in: XPath.FLOAT_DELAY, setting aside expanded
|
|
|
|
|
out: XPath.FLOAT_WINDOW
|
|
|
|
|
"""
|
2024-01-14 18:34:26 +00:00
|
|
|
|
while 1:
|
|
|
|
|
if skip_first:
|
|
|
|
|
skip_first = False
|
|
|
|
|
else:
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
|
|
|
|
|
if self.appear(XPath.FLOAT_WINDOW):
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if self.appear(XPath.FLOAT_DELAY, interval=3):
|
|
|
|
|
area = self.xpath(XPath.FLOAT_DELAY).area
|
|
|
|
|
area = area_offset(area, offset=(150, 0))
|
|
|
|
|
button = AreaButton(area=area, name='CLOUD_SETTING_EXIT')
|
|
|
|
|
self.device.click(button)
|
|
|
|
|
continue
|
|
|
|
|
|
2024-03-16 08:05:45 +00:00
|
|
|
|
def _cloud_setting_disable_net_state(self, skip_first=True):
|
|
|
|
|
"""
|
2024-05-30 04:16:25 +00:00
|
|
|
|
Disable net state display, or will cause detection error on COMBAT_AUTO, COMBAT_2X
|
|
|
|
|
|
2024-03-16 08:05:45 +00:00
|
|
|
|
Pages:
|
|
|
|
|
in: page_main
|
|
|
|
|
out: page_main
|
|
|
|
|
"""
|
|
|
|
|
self._cloud_setting_enter(skip_first=skip_first)
|
|
|
|
|
|
|
|
|
|
skip_first = True
|
|
|
|
|
while 1:
|
|
|
|
|
if skip_first:
|
|
|
|
|
skip_first = False
|
|
|
|
|
else:
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
|
|
|
|
|
button = self.xpath(XPath.SETTING_BITRATE_UHD)
|
|
|
|
|
if self.appear(button, interval=3):
|
|
|
|
|
if not button.selected:
|
|
|
|
|
logger.info('Set bitrate to UHD')
|
|
|
|
|
self.device.click(button)
|
|
|
|
|
continue
|
|
|
|
|
if self.appear(XPath.SETTING_NET_STATE_TOGGLE):
|
|
|
|
|
if self.appear(XPath.SETTING_NET_STATE_SIMPLE) or self.appear(XPath.SETTING_NET_STATE_DETAIL):
|
|
|
|
|
logger.info('Set net state to disabled')
|
|
|
|
|
self.appear_then_click(XPath.SETTING_NET_STATE_TOGGLE, interval=3)
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
logger.info('Net state display disabled')
|
|
|
|
|
break
|
|
|
|
|
# Scroll down
|
|
|
|
|
if not self.appear(XPath.SETTING_PROBLEM):
|
|
|
|
|
area = self.xpath(XPath.SCROLL_VIEW).area
|
|
|
|
|
# An area safe to swipe
|
|
|
|
|
area = (area[0], area[1], area[0] + 25, area[3])
|
|
|
|
|
p1, p2 = random_rectangle_vector_opted(
|
|
|
|
|
(0, -450), box=area, random_range=(-10, -30, 10, 30), padding=2)
|
|
|
|
|
self.device.swipe(p1, p2, name='SETTING_SCROLL')
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
self._cloud_setting_exit(skip_first=True)
|
|
|
|
|
|
|
|
|
|
def _cloud_net_state_appear(self):
|
|
|
|
|
"""
|
|
|
|
|
Returns:
|
|
|
|
|
bool: True if net state display is enabled
|
|
|
|
|
"""
|
|
|
|
|
if self.appear(XPath.FLOAT_STATE_SIMPLE):
|
|
|
|
|
logger.attr('Net state', 'FLOAT_STATE_SIMPLE')
|
|
|
|
|
return True
|
|
|
|
|
if self.appear(XPath.FLOAT_STATE_DETAIL):
|
|
|
|
|
logger.attr('Net state', 'FLOAT_STATE_DETAIL')
|
|
|
|
|
return True
|
|
|
|
|
logger.attr('Net state', None)
|
|
|
|
|
return False
|
|
|
|
|
|
2024-07-15 15:41:37 +00:00
|
|
|
|
def cloud_enter_game(self):
|
2024-03-16 08:05:45 +00:00
|
|
|
|
"""
|
2024-07-15 15:41:37 +00:00
|
|
|
|
Note that cloud game needs to be started before calling,
|
|
|
|
|
hierarchy needs to be updated before calling
|
|
|
|
|
|
2024-03-16 08:05:45 +00:00
|
|
|
|
Pages:
|
2024-07-15 15:41:37 +00:00
|
|
|
|
in: Any page in cloud game
|
2024-03-16 08:05:45 +00:00
|
|
|
|
out: page_main
|
|
|
|
|
"""
|
2024-07-15 15:41:37 +00:00
|
|
|
|
logger.hr('Cloud enter game', level=1)
|
2024-03-16 08:05:45 +00:00
|
|
|
|
|
2024-03-16 08:24:44 +00:00
|
|
|
|
with self.config.multi_set():
|
|
|
|
|
if self.config.Emulator_GameClient != 'cloud_android':
|
|
|
|
|
self.config.Emulator_GameClient = 'cloud_android'
|
|
|
|
|
if self.config.Emulator_PackageName != 'CN-Official':
|
|
|
|
|
self.config.Emulator_PackageName = 'CN-Official'
|
|
|
|
|
if self.config.Optimization_WhenTaskQueueEmpty != 'close_game':
|
|
|
|
|
self.config.Optimization_WhenTaskQueueEmpty = 'close_game'
|
2024-03-16 08:05:45 +00:00
|
|
|
|
|
2024-07-15 15:41:37 +00:00
|
|
|
|
if self.appear(XPath.START_GAME):
|
|
|
|
|
logger.info('Cloud game is in main page')
|
|
|
|
|
self._cloud_get_remain()
|
|
|
|
|
self._cloud_enter()
|
|
|
|
|
return True
|
2024-07-19 21:10:08 +00:00
|
|
|
|
elif self.is_in_cloud_page():
|
2024-07-15 15:41:37 +00:00
|
|
|
|
logger.info('Cloud game is in game')
|
|
|
|
|
return True
|
|
|
|
|
elif self.appear(XPath.FLOAT_DELAY):
|
|
|
|
|
logger.info('Cloud game is in game with float window expanded')
|
|
|
|
|
self._cloud_setting_exit()
|
|
|
|
|
return True
|
|
|
|
|
elif self.appear(XPath.POPUP_CONFIRM):
|
|
|
|
|
logger.info('Cloud game have a popup')
|
|
|
|
|
self._cloud_enter()
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self._cloud_start()
|
|
|
|
|
self._cloud_get_remain()
|
|
|
|
|
self._cloud_enter()
|
|
|
|
|
return True
|
2024-03-16 08:05:45 +00:00
|
|
|
|
|
2024-05-28 15:31:47 +00:00
|
|
|
|
def is_in_cloud_page(self):
|
|
|
|
|
if self.appear(XPath.START_GAME):
|
|
|
|
|
logger.info('Cloud game is in main page')
|
|
|
|
|
return True
|
2024-06-29 12:11:14 +00:00
|
|
|
|
if self.appear(XPath.FLOAT_DELAY):
|
2024-05-28 15:31:47 +00:00
|
|
|
|
logger.info('Cloud game is in game with float window expanded')
|
|
|
|
|
return True
|
2024-06-29 12:11:14 +00:00
|
|
|
|
if self.appear(XPath.POPUP_CONFIRM):
|
2024-05-28 15:31:47 +00:00
|
|
|
|
logger.info('Cloud game have a popup')
|
|
|
|
|
return True
|
2024-06-29 12:11:14 +00:00
|
|
|
|
if self.appear(XPath.ACCOUNT_LOGIN):
|
|
|
|
|
logger.info('Cloud game is at account login')
|
|
|
|
|
return True
|
2024-05-28 15:31:47 +00:00
|
|
|
|
|
|
|
|
|
logger.info('Not in cloud page')
|
|
|
|
|
return False
|
|
|
|
|
|
2024-07-15 15:41:37 +00:00
|
|
|
|
def cloud_try_enter_game(self):
|
2024-05-30 04:16:25 +00:00
|
|
|
|
"""
|
2024-07-15 15:41:37 +00:00
|
|
|
|
Note that hierarchy needs to be updated before calling
|
|
|
|
|
|
2024-05-30 04:16:25 +00:00
|
|
|
|
Pages:
|
|
|
|
|
in: Any page in cloud game
|
|
|
|
|
out: page_main
|
|
|
|
|
"""
|
2024-05-28 15:31:47 +00:00
|
|
|
|
if self.is_in_cloud_page():
|
2024-07-15 15:41:37 +00:00
|
|
|
|
self.cloud_enter_game()
|
2024-05-28 15:31:47 +00:00
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
2024-05-30 04:16:25 +00:00
|
|
|
|
def cloud_exit(self, skip_first=False):
|
|
|
|
|
"""
|
|
|
|
|
Exit cloud game, note that actively exit is recommended,
|
|
|
|
|
don't kill game directly, or will cause 3min extra fee because the sever side is still alive
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
skip_first: False by default because cloud_exit() is usually being called after running tasks,
|
|
|
|
|
existing hierarchy may be outdated
|
|
|
|
|
|
|
|
|
|
Pages:
|
|
|
|
|
in: XPath.FLOAT_WINDOW
|
|
|
|
|
out: XPath.START_GAME
|
|
|
|
|
"""
|
|
|
|
|
logger.hr('Cloud exit')
|
2024-05-30 14:03:41 +00:00
|
|
|
|
if not self.device.app_is_running():
|
|
|
|
|
logger.info('App is not running, no need to exit')
|
|
|
|
|
return
|
|
|
|
|
|
2024-05-30 04:16:25 +00:00
|
|
|
|
while 1:
|
|
|
|
|
if skip_first:
|
|
|
|
|
skip_first = False
|
|
|
|
|
else:
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
|
|
|
|
|
# End
|
|
|
|
|
if self.appear(XPath.START_GAME):
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if self.appear_then_click(XPath.FLOAT_WINDOW, interval=3):
|
|
|
|
|
continue
|
|
|
|
|
if self.appear_then_click(XPath.FLOAT_EXIT, interval=3):
|
|
|
|
|
continue
|
|
|
|
|
# 提示
|
|
|
|
|
# 是否确认退出游戏
|
|
|
|
|
# - 继续游戏 - 退出游戏
|
|
|
|
|
if self.appear_then_click(XPath.POPUP_CONFIRM, interval=3):
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# Update remain
|
2024-05-30 13:41:19 +00:00
|
|
|
|
if self.config.stored.CloudRemainSeasonPass:
|
|
|
|
|
self._cloud_get_remain()
|
|
|
|
|
else:
|
|
|
|
|
# Wait cloud remain reduce
|
|
|
|
|
# Value wasn't updated that fast at the time re-entering XPath.START_GAME
|
|
|
|
|
skip_first = True
|
|
|
|
|
timeout = Timer(2, count=4).start()
|
|
|
|
|
prev = [
|
|
|
|
|
self.config.stored.CloudRemainSeasonPass.value,
|
|
|
|
|
self.config.stored.CloudRemainPaid.value,
|
|
|
|
|
self.config.stored.CloudRemainFree.value,
|
|
|
|
|
]
|
|
|
|
|
with self.config.multi_set():
|
|
|
|
|
while 1:
|
|
|
|
|
if skip_first:
|
|
|
|
|
skip_first = False
|
|
|
|
|
else:
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
|
|
|
|
|
# End
|
|
|
|
|
if timeout.reached():
|
|
|
|
|
logger.warning('Wait cloud remain reduce timeout')
|
|
|
|
|
break
|
|
|
|
|
self._cloud_get_remain()
|
|
|
|
|
current = [
|
|
|
|
|
self.config.stored.CloudRemainSeasonPass.value,
|
|
|
|
|
self.config.stored.CloudRemainPaid.value,
|
|
|
|
|
self.config.stored.CloudRemainFree.value,
|
|
|
|
|
]
|
|
|
|
|
if current != prev:
|
|
|
|
|
break
|
2024-05-30 04:16:25 +00:00
|
|
|
|
|
2024-05-30 14:03:41 +00:00
|
|
|
|
logger.info('Cloud exited')
|
|
|
|
|
|
2024-03-16 08:05:45 +00:00
|
|
|
|
def cloud_keep_alive(self):
|
|
|
|
|
"""
|
|
|
|
|
Randomly do something to prevent being kicked
|
|
|
|
|
|
|
|
|
|
WARNING:
|
|
|
|
|
this may cause extra fee
|
|
|
|
|
"""
|
|
|
|
|
logger.hr('cloud_keep_alive', level=2)
|
|
|
|
|
while 1:
|
|
|
|
|
self.device.sleep((45, 60))
|
|
|
|
|
|
|
|
|
|
logger.info('cloud_keep_alive')
|
|
|
|
|
self._cloud_setting_enter(skip_first=False)
|
|
|
|
|
self._cloud_setting_exit(skip_first=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
self = LoginAndroidCloud('src')
|
2024-07-15 15:41:37 +00:00
|
|
|
|
self.device.app_start()
|
|
|
|
|
self.device.dump_hierarchy()
|
|
|
|
|
self.cloud_enter_game()
|
2024-03-16 08:05:45 +00:00
|
|
|
|
self.cloud_keep_alive()
|