Merge branch 'master' into dev

# Conflicts:
#	dev_tools/keyword_extract.py
This commit is contained in:
LmeSzinc 2023-10-17 19:01:09 +08:00
commit 084ada106f
29 changed files with 373 additions and 25 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -155,6 +155,17 @@
"StallerJade": {}
}
},
"Freebies": {
"Scheduler": {
"Enable": true,
"NextRun": "2020-01-01 00:00:00",
"Command": "Freebies",
"ServerUpdate": "04:00"
},
"SupportReward": {
"Collect": true
}
},
"Rogue": {
"Scheduler": {
"Enable": false,

View File

@ -147,10 +147,10 @@ class ButtonWrapper(Resource):
self.name = name
self.data_buttons = kwargs
self._matched_button: t.Optional[Button] = None
self.resource_add(self.name)
self.resource_add(f'{name}:{next(self.iter_buttons(), None)}')
def resource_release(self):
del_cached_property(self, 'assets')
del_cached_property(self, 'buttons')
self._matched_button = None
def __str__(self):

View File

@ -1,11 +1,11 @@
import re
import module.config.server as server
from module.base.decorator import cached_property, del_cached_property
from module.base.decorator import cached_property
def get_assets_from_file(file, regex):
def get_assets_from_file(file):
assets = set()
regex = re.compile(r"file='(.*?)'")
with open(file, 'r', encoding='utf-8') as f:
for row in f.readlines():
result = regex.search(row)
@ -20,11 +20,12 @@ class PreservedAssets:
assets = set()
assets |= get_assets_from_file(
file='./tasks/base/assets/assets_base_page.py',
regex=re.compile(r'^([A-Za-z][A-Za-z0-9_]+) = ')
)
assets |= get_assets_from_file(
file='./tasks/base/assets/assets_base_popup.py',
regex=re.compile(r'^([A-Za-z][A-Za-z0-9_]+) = ')
)
assets |= get_assets_from_file(
file='./tasks/base/assets/assets_base_main_page.py',
)
return assets
@ -44,11 +45,13 @@ class Resource:
@classmethod
def is_loaded(cls, obj):
if hasattr(obj, '_image') and obj._image is None:
return False
elif hasattr(obj, 'image') and obj.image is None:
return False
return True
if hasattr(obj, '_image') and obj._image is not None:
return True
if hasattr(obj, 'image') and obj.image is not None:
return True
if hasattr(obj, 'buttons') and obj.buttons is not None:
return True
return False
@classmethod
def resource_show(cls):
@ -56,11 +59,16 @@ class Resource:
logger.hr('Show resource')
for key, obj in cls.instances.items():
if cls.is_loaded(obj):
continue
logger.info(f'{obj}: {key}')
logger.info(f'{obj}: {key}')
def release_resources(next_task=''):
# Release all OCR models
# det models take 400MB
if not next_task:
from module.ocr.models import OCR_MODEL
OCR_MODEL.resource_release()
# Release assets cache
# module.ui has about 80 assets and takes about 3MB
# Alas has about 800 assets, but they are not all loaded.

View File

@ -1110,6 +1110,39 @@
}
}
},
"Freebies": {
"Scheduler": {
"Enable": {
"type": "checkbox",
"value": true,
"option": [
true,
false
]
},
"NextRun": {
"type": "datetime",
"value": "2020-01-01 00:00:00",
"validate": "datetime"
},
"Command": {
"type": "input",
"value": "Freebies",
"display": "hide"
},
"ServerUpdate": {
"type": "input",
"value": "04:00",
"display": "hide"
}
},
"SupportReward": {
"Collect": {
"type": "checkbox",
"value": true
}
}
},
"Rogue": {
"Scheduler": {
"Enable": {

View File

@ -126,6 +126,8 @@ DungeonStorage:
stored: StoredSimulatedUniverse
order: 6
color: "#8fb5fe"
SupportReward:
Collect: true
Weekly:
Name:

View File

@ -22,3 +22,6 @@ BattlePass:
Assignment:
Scheduler:
Enable: true
Freebies:
Scheduler:
Enable: true

View File

@ -16,7 +16,8 @@
"DailyQuest",
"BattlePass",
"Assignment",
"DataUpdate"
"DataUpdate",
"Freebies"
]
}
}

View File

@ -44,7 +44,9 @@ Daily:
DataUpdate:
- Scheduler
- ItemStorage
Freebies:
- Scheduler
- SupportReward
# ==================== Rogue ====================
Rogue:

View File

@ -61,6 +61,9 @@ class GeneratedConfig:
DungeonStorage_EchoOfWar = {}
DungeonStorage_SimulatedUniverse = {}
# Group `SupportReward`
SupportReward_Collect = True
# Group `Weekly`
Weekly_Name = 'Echo_of_War_Divine_Seed' # Echo_of_War_Destruction_Beginning, Echo_of_War_End_of_the_Eternal_Freeze, Echo_of_War_Divine_Seed
Weekly_Team = 1 # 1, 2, 3, 4, 5, 6

View File

@ -10,7 +10,8 @@ class ManualConfig:
SCHEDULER_PRIORITY = """
Restart
> BattlePass > DailyQuest > Assignment > DataUpdate
> BattlePass > DailyQuest > Assignment
> Freebies > DataUpdate
> Weekly > Dungeon
"""

View File

@ -46,6 +46,10 @@
"name": "Dashboard Upd",
"help": ""
},
"Freebies": {
"name": "Freebies",
"help": ""
},
"Rogue": {
"name": "Simulated Universe",
"help": "Simulated Universe is in development, task will not be run"
@ -410,6 +414,16 @@
"help": ""
}
},
"SupportReward": {
"_info": {
"name": "Support Reward",
"help": ""
},
"Collect": {
"name": "Receive support reward",
"help": ""
}
},
"Weekly": {
"_info": {
"name": "Echo of War Settings",

View File

@ -46,6 +46,10 @@
"name": "Actualizar panel",
"help": ""
},
"Freebies": {
"name": "Freebies",
"help": ""
},
"Rogue": {
"name": "Universo Simulado",
"help": "El Universo Simulado está en desarrollo, y no se ejecutará"
@ -410,6 +414,16 @@
"help": ""
}
},
"SupportReward": {
"_info": {
"name": "Support Reward",
"help": ""
},
"Collect": {
"name": "Receive support reward",
"help": ""
}
},
"Weekly": {
"_info": {
"name": "Ajustes de Ecos de la guerra",

View File

@ -46,6 +46,10 @@
"name": "Task.DataUpdate.name",
"help": "Task.DataUpdate.help"
},
"Freebies": {
"name": "他ギフト",
"help": ""
},
"Rogue": {
"name": "Task.Rogue.name",
"help": "Task.Rogue.help"
@ -410,6 +414,16 @@
"help": "DungeonStorage.SimulatedUniverse.help"
}
},
"SupportReward": {
"_info": {
"name": "サポートボーナス",
"help": ""
},
"Collect": {
"name": "收取サポートボーナス",
"help": ""
}
},
"Weekly": {
"_info": {
"name": "Weekly._info.name",

View File

@ -46,6 +46,10 @@
"name": "仪表盘更新",
"help": ""
},
"Freebies": {
"name": "白嫖奖励",
"help": ""
},
"Rogue": {
"name": "模拟宇宙",
"help": "模拟宇宙还在开发中,任务不会被运行"
@ -410,6 +414,16 @@
"help": ""
}
},
"SupportReward": {
"_info": {
"name": "支援奖励",
"help": ""
},
"Collect": {
"name": "领取支援奖励",
"help": ""
}
},
"Weekly": {
"_info": {
"name": "历战余响设置",

View File

@ -46,6 +46,10 @@
"name": "儀表板更新",
"help": ""
},
"Freebies": {
"name": "免費獎勵",
"help": ""
},
"Rogue": {
"name": "模擬宇宙",
"help": "模擬宇宙還在開發中,任務不會被運行"
@ -410,6 +414,16 @@
"help": ""
}
},
"SupportReward": {
"_info": {
"name": "支援獎勵",
"help": ""
},
"Collect": {
"name": "收取支援獎勵",
"help": ""
}
},
"Weekly": {
"_info": {
"name": "歷戰餘響設定",

View File

@ -1,6 +1,6 @@
from pponnxcr import TextSystem as TextSystem_
from module.base.decorator import cached_property
from module.base.decorator import cached_property, del_cached_property
from module.exception import ScriptError
DIC_LANG_TO_MODEL = {
@ -56,6 +56,12 @@ class OcrModel:
except AttributeError:
raise ScriptError(f'OCR model under lang "{lang}" does not exists')
def resource_release(self):
del_cached_property(self, 'zhs')
del_cached_property(self, 'en')
del_cached_property(self, 'ja')
del_cached_property(self, 'zht')
@cached_property
def zhs(self):
return TextSystem('zhs')
@ -66,7 +72,7 @@ class OcrModel:
@cached_property
def ja(self):
return TextSystem('zht')
return TextSystem('ja')
@cached_property
def zht(self):

3
src.py
View File

@ -46,6 +46,9 @@ class StarRailCopilot(AzurLaneAutoScript):
from tasks.item.data_update import DataUpdate
DataUpdate(config=self.config, device=self.device).run()
def freebies(self):
from tasks.freebies.freebies import Freebies
Freebies(config=self.config, device=self.device).run()
if __name__ == '__main__':
src = StarRailCopilot('src')

View File

@ -1,18 +1,26 @@
from module.base.base import ModuleBase
from module.logger import logger
from tasks.base.assets.assets_base_popup import *
class PopupHandler(ModuleBase):
def handle_reward(self, interval=5) -> bool:
def handle_reward(self, interval=5, click_button=None) -> bool:
"""
Args:
interval:
click_button: Set a button to click
Returns:
If handled.
"""
if self.appear_then_click(GET_REWARD, interval=interval):
return True
if click_button is None:
if self.appear_then_click(GET_REWARD, interval=interval):
return True
else:
if self.appear(GET_REWARD, interval=interval):
logger.info(f'{GET_REWARD} -> {click_button}')
self.device.click(click_button)
return True
return False

View File

@ -1,3 +1,5 @@
import re
import numpy as np
from module.base.base import ModuleBase
@ -70,6 +72,9 @@ class OcrDungeonList(Ocr):
if self.lang == 'cn':
result = result.replace('', '') # 巽风之形
result = result.replace('皖A0', '50').replace('', '')
# 燔灼之形•凝滞虚影
result = result.replace('', '')
result = re.sub('^灼之形', '燔灼之形', result)
return result
@ -411,7 +416,7 @@ class DungeonUI(UI):
Examples:
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_LIST
self = DungeonUI('alas')
self = DungeonUI('src')
self.device.screenshot()
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
self.dungeon_goto(KEYWORDS_DUNGEON_LIST.Calyx_Crimson_Harmony)

View File

@ -13,7 +13,7 @@ from tasks.base.assets.assets_base_page import FORGOTTEN_HALL_CHECK, MAP_EXIT
from tasks.dungeon.keywords import DungeonList, KEYWORDS_DUNGEON_LIST, KEYWORDS_DUNGEON_TAB
from tasks.dungeon.ui import DungeonUI
from tasks.forgotten_hall.assets.assets_forgotten_hall_ui import *
from tasks.forgotten_hall.keywords import ForgottenHallStage
from tasks.forgotten_hall.keywords import ForgottenHallStage, KEYWORDS_FORGOTTEN_HALL_STAGE
from tasks.forgotten_hall.team import ForgottenHallTeam
from tasks.map.control.joystick import MapControlJoystick
@ -70,7 +70,11 @@ class DraggableStageList(DraggableList):
while 1:
result = super().insight_row(row, main=main, skip_first_screenshot=skip_first_screenshot)
if not result:
return False
if row == KEYWORDS_FORGOTTEN_HALL_STAGE.Stage_1:
# Must have stage 1, retry if not found
continue
else:
return False
if skip_first_screenshot:
skip_first_screenshot = False

View File

@ -0,0 +1,62 @@
from module.base.button import Button, ButtonWrapper
# This file was auto-generated, do not modify it manually. To generate:
# ``` python -m dev_tools.button_extract ```
CAN_GET_REWARD = ButtonWrapper(
name='CAN_GET_REWARD',
share=Button(
file='./assets/share/freebies/support_reward/CAN_GET_REWARD.png',
area=(1055, 266, 1106, 310),
search=(1035, 246, 1126, 330),
color=(229, 186, 123),
button=(1055, 266, 1106, 310),
),
)
CLICKING_REWARD = ButtonWrapper(
name='CLICKING_REWARD',
share=Button(
file='./assets/share/freebies/support_reward/CLICKING_REWARD.png',
area=(1066, 268, 1105, 307),
search=(1046, 248, 1125, 327),
color=(197, 161, 111),
button=(1066, 268, 1105, 307),
),
)
IN_PROFILE = ButtonWrapper(
name='IN_PROFILE',
share=Button(
file='./assets/share/freebies/support_reward/IN_PROFILE.png',
area=(643, 106, 673, 131),
search=(623, 86, 693, 151),
color=(74, 67, 58),
button=(643, 106, 673, 131),
),
)
MENU_TO_PROFILE = ButtonWrapper(
name='MENU_TO_PROFILE',
share=Button(
file='./assets/share/freebies/support_reward/MENU_TO_PROFILE.png',
area=(1123, 82, 1149, 97),
search=(1103, 62, 1169, 117),
color=(226, 226, 225),
button=(1123, 82, 1149, 97),
),
)
PROFILE = ButtonWrapper(
name='PROFILE',
cn=Button(
file='./assets/cn/freebies/support_reward/PROFILE.png',
area=(890, 99, 1111, 131),
search=(870, 79, 1131, 151),
color=(205, 206, 206),
button=(890, 99, 1111, 131),
),
en=Button(
file='./assets/en/freebies/support_reward/PROFILE.png',
area=(907, 102, 1092, 132),
search=(887, 82, 1112, 152),
color=(190, 189, 189),
button=(907, 102, 1092, 132),
),
)

View File

@ -0,0 +1,14 @@
from module.logger import logger
from module.base.base import ModuleBase
from tasks.freebies.support_reward import SupportReward
class Freebies(ModuleBase):
def run(self):
"""
Run all freebie tasks
"""
if self.config.SupportReward_Collect:
logger.hr('Support Reward')
SupportReward(config=self.config, device=self.device).run()
self.config.task_delay(server_update=True)

View File

@ -0,0 +1,112 @@
from module.base.timer import Timer
from module.logger import logger
from tasks.base.assets.assets_base_page import CLOSE, MENU_CHECK
from tasks.base.assets.assets_base_popup import GET_REWARD
from tasks.base.page import page_menu
from tasks.base.ui import UI
from tasks.freebies.assets.assets_freebies_support_reward import (
CAN_GET_REWARD,
IN_PROFILE,
MENU_TO_PROFILE,
PROFILE
)
class SupportReward(UI):
def run(self):
"""
Run get support reward task
"""
logger.hr('Support reward', level=1)
self.ui_ensure(page_menu)
self._goto_profile()
self._get_reward()
self._goto_menu()
def _goto_profile(self):
"""
Pages:
in: MENU
out: PROFILE
"""
skip_first_screenshot = False
logger.info('Going to profile')
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.appear(IN_PROFILE):
logger.info('Successfully in profile')
return True
if self.appear_then_click(MENU_TO_PROFILE):
continue
if self.appear_then_click(PROFILE):
continue
def _get_reward(self, skip_first_screenshot=True):
"""
Pages:
in: PROFILE
out: GET_REWARD
"""
logger.info('Getting reward')
claimed = False
empty = Timer(0.3, count=1).start()
timeout = Timer(5).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if not claimed and empty.reached():
logger.info('No reward')
break
if self.appear(GET_REWARD):
logger.info('Got reward')
break
if timeout.reached():
logger.warning('Get support reward timeout')
break
if self.appear_then_click(CAN_GET_REWARD, similarity=0.70, interval=2):
claimed = True
timeout.reset()
continue
def _goto_menu(self):
"""
Pages:
in: PROFILE or GET_REWARD
out: MENU
"""
skip_first_screenshot = False
logger.info('Going to menu')
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.appear(MENU_CHECK):
return True
if self.appear(IN_PROFILE, interval=2):
logger.info(f'{IN_PROFILE} -> {CLOSE}')
self.device.click(CLOSE)
continue
if self.handle_reward(click_button=CAN_GET_REWARD):
# # Avoid clicking on some other buttons
continue
if __name__ == '__main__':
self = SupportReward('src')
self.device.screenshot()
self.run()