1
0
mirror of https://github.com/TheFunny/ArisuAutoSweeper synced 2026-06-28 19:34:56 +00:00

2 Commits

Author SHA1 Message Date
RedDeadDepresso 5feb46040c added more images 2023-11-12 22:44:09 +00:00
RedDeadDepresso bc920f065d added en folder 2023-11-12 21:30:23 +00:00
129 changed files with 202 additions and 2782 deletions
+3 -10
View File
@@ -12,17 +12,12 @@
The script is still under active development. The following features have been implemented:
- [x] **Cafe** Claim rewards / Interact / Second floor
- [x] **Club** Claim AP
- [x] **Cafe** Claim rewards / Interact / Second cafe
- [x] **Circle** Claim AP
- [x] **Mailbox** Claim rewards
- [x] **Bounty** Auto sweep
- [x] **Scrimmage** Auto sweep
- [x] **Tactical Challenge** Claim rewards / Auto battle
Supported servers:
- [x] JP
- [x] OVERSEA - Global
_Currently only supports JP server._
## Relative projects
@@ -43,5 +38,3 @@ Thanks to [6bir](https://github.com/6bir) for the icon design.
Thanks to [Alas](https://github.com/LmeSzinc/AzurLaneAutoScript) and [SRC](https://github.com/LmeSzinc/StarRailCopilot)
for the development framework.
Thanks to [RedDeadDepresso](https://github.com/RedDeadDepresso) for EN support.
+1 -16
View File
@@ -15,22 +15,9 @@
- [x] **咖啡厅** 领取奖励 / 互动 / 第二咖啡厅
- [x] **公会** 领取体力
- [x] **邮箱** 领取奖励
- [x] **悬赏通缉** 自动扫荡
- [x] **学院交流会** 自动扫荡
- [x] **战术对抗赛** 领取奖励 / 自动战斗
目前支持的服务器:
- [x] 日服
- [x] 国际服 - 全球
## 已知问题
若愿意提供其他服务器支持,请开 PR 或 Issue。
- **大小月卡**:未实现自动领取,~~因为没买过~~,可能不影响使用。愿意提供图片的请开 Issue
- **月卡的额外悬赏券和学院交流券**:不太清楚月卡领取额外券的机制,~~因为没买过~~,可能影响相关任务使用券和体力的计算。愿意提供相关信息的请开
Issue
_目前支持日服。_
## 相关项目
@@ -49,5 +36,3 @@
感谢 [Alas](https://github.com/LmeSzinc/AzurLaneAutoScript) 以及 [SRC](https://github.com/LmeSzinc/StarRailCopilot)
提供的开发框架。
感谢 [RedDeadDepresso](https://github.com/RedDeadDepresso) 提供英语支持。
-8
View File
@@ -34,14 +34,6 @@ class ArisuAutoSweeper(AzurLaneAutoScript):
from tasks.mail.mail import Mail
Mail(config=self.config, device=self.device).run()
def bounty(self):
from tasks.bounty.bounty import Bounty
Bounty(config=self.config, device=self.device).run()
def scrimmage(self):
from tasks.scrimmage.scrimmage import Scrimmage
Scrimmage(config=self.config, device=self.device).run()
def tactical_challenge(self):
from tasks.tactical_challenge.tactical_challenge import TacticalChallenge
TacticalChallenge(config=self.config, device=self.device).run()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

+1 -1
View File
@@ -285,7 +285,7 @@ pre.rich-traceback-code {
*[style*="--header-icon--"] {
margin: .25rem auto .25rem;
border-radius: 1.5rem;
height: 3em;
height: 3.5em;
}
*[style*="--header-text--"] {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

+2 -2
View File
@@ -1,8 +1,8 @@
Deploy:
Git:
# URL of AzurLaneAutoScript repository
# [CN user] Use 'cn' to get update from self-hosted git service
# [Other] Use 'global' to get update from https://github.com/TheFunny/ArisuAutoSweeper
# [CN user] Use 'cn' to get update from git-over-cdn service
# [Other] Use 'global' to get update from https://github.com/TheFunny/ArisuAutoSrcipt
Repository: cn
# Branch of Alas
# [Developer] Use 'dev', 'app', etc, to try new features
+2 -2
View File
@@ -1,8 +1,8 @@
Deploy:
Git:
# URL of AzurLaneAutoScript repository
# [CN user] Use 'cn' to get update from self-hosted git service
# [Other] Use 'global' to get update from https://github.com/TheFunny/ArisuAutoSweeper
# [CN user] Use 'cn' to get update from git-over-cdn service
# [Other] Use 'global' to get update from https://github.com/TheFunny/ArisuAutoSrcipt
Repository: global
# Branch of Alas
# [Developer] Use 'dev', 'app', etc, to try new features
+1 -50
View File
@@ -63,52 +63,6 @@
"ServerUpdate": "04:00"
}
},
"Bounty": {
"Scheduler": {
"Enable": true,
"NextRun": "2020-01-01 00:00:00",
"Command": "Bounty",
"ServerUpdate": "04:00"
},
"Bounty": {
"OnError": "skip"
},
"Highway": {
"Stage": 1,
"Count": 2
},
"DesertRailroad": {
"Stage": 1,
"Count": 2
},
"Schoolhouse": {
"Stage": 1,
"Count": 2
}
},
"Scrimmage": {
"Scheduler": {
"Enable": true,
"NextRun": "2020-01-01 00:00:00",
"Command": "Scrimmage",
"ServerUpdate": "04:00"
},
"Scrimmage": {
"OnError": "skip"
},
"Trinity": {
"Stage": 1,
"Count": 2
},
"Gehenna": {
"Stage": 1,
"Count": 2
},
"Millennium": {
"Stage": 1,
"Count": 2
}
},
"TacticalChallenge": {
"Scheduler": {
"Enable": true,
@@ -130,10 +84,7 @@
"ItemStorage": {
"AP": {},
"Credit": {},
"Pyroxene": {},
"BountyTicket": {},
"ScrimmageTicket": {},
"TacticalChallengeTicket": {}
"Pyroxene": {}
}
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
Deploy:
Git:
# URL of AzurLaneAutoScript repository
# [CN user] Use 'cn' to get update from self-hosted git service
# [Other] Use 'global' to get update from https://github.com/TheFunny/ArisuAutoSweeper
# [CN user] Use 'cn' to get update from git-over-cdn service
# [Other] Use 'global' to get update from https://github.com/TheFunny/ArisuAutoSrcipt
Repository: 'global'
# Branch of Alas
# [Developer] Use 'dev', 'app', etc, to try new features
+7 -16
View File
@@ -179,29 +179,20 @@ def iter_assets():
if image.attr != '':
row = deep_get(data, keys=[image.module, image.assets, image.server, image.frame])
row.load_image(image)
# Set `search`
# Apply `search` of the first frame to all
for path, frames in deep_iter(data, depth=3):
print(path, frames)
# If `search` attribute is set in the first frame, apply to all
first = frames[1]
if first.search:
for frame in frames.values():
frame.search = first.search
else:
for frame in frames.values():
if frame.search:
# Follow frame specific `search`
pass
else:
# Generate `search` from `area`
frame.search = DataAssets.area_to_search(frame.area)
search = first.search if first.search else DataAssets.area_to_search(first.area)
for frame in frames.values():
frame.search = search
return data
def generate_code():
all_assets = iter_assets()
for module, module_data in all_assets.items():
all = iter_assets()
for module, module_data in all.items():
path = os.path.join(AzurLaneConfig.ASSETS_MODULE, module.split('/', maxsplit=1)[0])
output = os.path.join(path, 'assets.py')
if os.path.exists(output):
@@ -213,7 +204,7 @@ def generate_code():
continue
os.remove(prev)
for module, module_data in all_assets.items():
for module, module_data in all.items():
path = os.path.join(AzurLaneConfig.ASSETS_MODULE, module.split('/', maxsplit=1)[0])
output = os.path.join(path, 'assets')
gen = CodeGenerator()
+21 -101
View File
@@ -74,7 +74,7 @@ class Button(Resource):
threshold=threshold
)
def match_template(self, image, similarity=0.85, direct_match=False) -> bool:
def match_template(self, image, similarity=0.85) -> bool:
"""
Detects assets by template matching.
@@ -83,45 +83,18 @@ class Button(Resource):
Args:
image: Screenshot.
similarity (float): 0-1.
direct_match: True to ignore `self.search`
Returns:
bool.
"""
if not direct_match:
image = crop(image, self.search, copy=False)
image = crop(image, self.search, copy=False)
res = cv2.matchTemplate(self.image, image, cv2.TM_CCOEFF_NORMED)
_, sim, _, point = cv2.minMaxLoc(res)
self._button_offset = np.array(point) + self.search[:2] - self.area[:2]
return sim > similarity
def match_multi_template(self, image, similarity=0.85, direct_match=False):
"""
Detects assets by template matching, return multiple reults
Args:
image: Screenshot.
similarity (float): 0-1.
direct_match: True to ignore `self.search`
Returns:
list:
"""
if not direct_match:
image = crop(image, self.search, copy=False)
res = cv2.matchTemplate(self.image, image, cv2.TM_CCOEFF_NORMED)
res = cv2.inRange(res, similarity, 1.)
try:
points = np.array(cv2.findNonZero(res))[:, 0, :]
points += self.search[:2]
return points.tolist()
except IndexError:
# Empty result
# IndexError: too many indices for array: array is 0-dimensional, but 3 were indexed
return []
def match_template_color(self, image, similarity=0.85, threshold=30, direct_match=False) -> bool:
def match_template_color(self, image, similarity=0.85, threshold=30) -> bool:
"""
Template match first, color match then
@@ -129,12 +102,11 @@ class Button(Resource):
image: Screenshot.
similarity (float): 0-1.
threshold (int): Default to 10.
direct_match: True to ignore `self.search`
Returns:
bool.
"""
matched = self.match_template(image, similarity=similarity, direct_match=direct_match)
matched = self.match_template(image, similarity=similarity)
if not matched:
return False
@@ -152,10 +124,10 @@ class ButtonWrapper(Resource):
self.name = name
self.data_buttons = kwargs
self._matched_button: t.Optional[Button] = None
self.resource_add(f'{name}:{next(self.iter_buttons(), None)}')
self.resource_add(self.name)
def resource_release(self):
del_cached_property(self, 'buttons')
del_cached_property(self, 'assets')
self._matched_button = None
def __str__(self):
@@ -172,25 +144,16 @@ class ButtonWrapper(Resource):
def __bool__(self):
return True
def iter_buttons(self) -> t.Iterator[Button]:
for _, assets in self.data_buttons.items():
if isinstance(assets, Button):
yield assets
elif isinstance(assets, list):
for asset in assets:
yield asset
@cached_property
def buttons(self) -> t.List[Button]:
for trial in [server.lang, 'share', 'cn']:
try:
assets = self.data_buttons[trial]
# for trial in [server.lang, 'share', 'cn']:
for trial in [server.lang, 'share', 'jp']:
assets = self.data_buttons.get(trial, None)
if assets is not None:
if isinstance(assets, Button):
return [assets]
elif isinstance(assets, list):
return assets
except KeyError:
pass
raise ScriptError(f'ButtonWrapper({self}) on server {server.lang} has no fallback button')
@@ -201,45 +164,16 @@ class ButtonWrapper(Resource):
return True
return False
def match_template(self, image, similarity=0.85, direct_match=False) -> bool:
def match_template(self, image, similarity=0.85) -> bool:
for assets in self.buttons:
if assets.match_template(image, similarity=similarity, direct_match=direct_match):
if assets.match_template(image, similarity=similarity):
self._matched_button = assets
return True
return False
def match_multi_template(self, image, similarity=0.85, threshold=5, direct_match=False):
"""
Detects assets by template matching, return multiple results
Args:
image: Screenshot.
similarity (float): 0-1.
threshold:
direct_match: True to ignore `self.search`
Returns:
list[ClickButton]:
"""
ps = []
def match_template_color(self, image, similarity=0.85, threshold=30) -> bool:
for assets in self.buttons:
ps += assets.match_multi_template(image, similarity=similarity, direct_match=direct_match)
if not ps:
return []
from module.base.utils.points import Points
ps = Points(ps).group(threshold=threshold)
area_list = [area_offset(self.area, p - self.area[:2]) for p in ps]
button_list = [area_offset(self.button, p - self.area[:2]) for p in ps]
return [
ClickButton(area=info[0], button=info[1], name=f'{self.name}_result{i}')
for i, info in enumerate(zip(area_list, button_list))
]
def match_template_color(self, image, similarity=0.85, threshold=30, direct_match=False) -> bool:
for assets in self.buttons:
if assets.match_template_color(
image, similarity=similarity, threshold=threshold, direct_match=direct_match):
if assets.match_template_color(image, similarity=similarity, threshold=threshold):
self._matched_button = assets
return True
return False
@@ -288,32 +222,18 @@ class ButtonWrapper(Resource):
"""
if isinstance(button, ButtonWrapper):
button = button.matched_button
for b in self.iter_buttons():
for b in self.buttons:
b.load_offset(button)
def clear_offset(self):
for b in self.iter_buttons():
for b in self.buttons:
b.clear_offset()
def load_search(self, area):
"""
Set `search` attribute.
Note that this method is irreversible.
Args:
area:
"""
for b in self.iter_buttons():
b.search = area
class ClickButton:
def __init__(self, area, button=None, name='CLICK_BUTTON'):
self.area = area
if button is None:
self.button = area
else:
self.button = button
def __init__(self, button, name='CLICK_BUTTON'):
self.area = button
self.button = button
self.name = name
def __str__(self):
@@ -345,4 +265,4 @@ def match_template(image, template, similarity=0.85):
"""
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
_, sim, _, point = cv2.minMaxLoc(res)
return sim > similarity
return sim > similarity
+13 -18
View File
@@ -1,11 +1,11 @@
import re
from module.base.decorator import cached_property
import module.config.server as server
from module.base.decorator import cached_property, del_cached_property
def get_assets_from_file(file):
def get_assets_from_file(file, regex):
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,9 +20,11 @@ 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_]+) = ')
)
return assets
@@ -42,13 +44,11 @@ class Resource:
@classmethod
def is_loaded(cls, obj):
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
if hasattr(obj, '_image') and obj._image is None:
return False
elif hasattr(obj, 'image') and obj.image is None:
return False
return True
@classmethod
def resource_show(cls):
@@ -56,16 +56,11 @@ class Resource:
logger.hr('Show resource')
for key, obj in cls.instances.items():
if cls.is_loaded(obj):
logger.info(f'{obj}: {key}')
continue
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.
@@ -79,4 +74,4 @@ def release_resources(next_task=''):
obj.resource_release()
# Useless in most cases, but just call it
# gc.collect()
# gc.collect()
+2 -213
View File
@@ -11,8 +11,7 @@
"value": "auto",
"option": [
"auto",
"JP-Official",
"OVERSEA-Global"
"JP-Official"
]
},
"GameLanguage": {
@@ -20,8 +19,7 @@
"value": "auto",
"option": [
"auto",
"jp",
"en"
"jp"
]
},
"ScreenshotMethod": {
@@ -257,191 +255,6 @@
}
}
},
"Bounty": {
"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": "Bounty",
"display": "hide"
},
"ServerUpdate": {
"type": "input",
"value": "04:00",
"display": "hide"
}
},
"Bounty": {
"OnError": {
"type": "select",
"value": "skip",
"option": [
"stop",
"skip"
]
}
},
"Highway": {
"Stage": {
"type": "select",
"value": 1,
"option": [
1,
2,
3,
4,
5,
6,
7,
8,
9
]
},
"Count": {
"type": "input",
"value": 2
}
},
"DesertRailroad": {
"Stage": {
"type": "select",
"value": 1,
"option": [
1,
2,
3,
4,
5,
6,
7,
8,
9
]
},
"Count": {
"type": "input",
"value": 2
}
},
"Schoolhouse": {
"Stage": {
"type": "select",
"value": 1,
"option": [
1,
2,
3,
4,
5,
6,
7,
8,
9
]
},
"Count": {
"type": "input",
"value": 2
}
}
},
"Scrimmage": {
"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": "Scrimmage",
"display": "hide"
},
"ServerUpdate": {
"type": "input",
"value": "04:00",
"display": "hide"
}
},
"Scrimmage": {
"OnError": {
"type": "select",
"value": "skip",
"option": [
"stop",
"skip"
]
}
},
"Trinity": {
"Stage": {
"type": "select",
"value": 1,
"option": [
1,
2,
3,
4
]
},
"Count": {
"type": "input",
"value": 2
}
},
"Gehenna": {
"Stage": {
"type": "select",
"value": 1,
"option": [
1,
2,
3,
4
]
},
"Count": {
"type": "input",
"value": 2
}
},
"Millennium": {
"Stage": {
"type": "select",
"value": 1,
"option": [
1,
2,
3,
4
]
},
"Count": {
"type": "input",
"value": 2
}
}
},
"TacticalChallenge": {
"Scheduler": {
"Enable": {
@@ -533,30 +346,6 @@
"stored": "StoredInt",
"order": 3,
"color": "#21befc"
},
"BountyTicket": {
"type": "stored",
"value": {},
"display": "hide",
"stored": "StoredBountyTicket",
"order": 4,
"color": "#94cb44"
},
"ScrimmageTicket": {
"type": "stored",
"value": {},
"display": "hide",
"stored": "StoredScrimmageTicket",
"order": 5,
"color": "#f86c6a"
},
"TacticalChallengeTicket": {
"type": "stored",
"value": {},
"display": "hide",
"stored": "StoredTacticalChallengeTicket",
"order": 6,
"color": "#7ac8e5"
}
}
}
+1 -55
View File
@@ -23,7 +23,7 @@ Emulator:
option: [ auto, ]
GameLanguage:
value: auto
option: [ auto, jp, en ]
option: [ auto, jp ]
ScreenshotMethod:
value: auto
option: [ auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, scrcpy ]
@@ -81,48 +81,6 @@ Cafe:
AutoAdjust: true
SecondCafe: true
Bounty:
OnError:
value: skip
option: [ stop, skip ]
Highway:
Stage:
value: 1
option: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Count: 2
DesertRailroad:
Stage:
value: 1
option: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Count: 2
Schoolhouse:
Stage:
value: 1
option: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Count: 2
Scrimmage:
OnError:
value: skip
option: [ stop, skip ]
Trinity:
Stage:
value: 1
option: [ 1, 2, 3, 4 ]
Count: 2
Gehenna:
Stage:
value: 1
option: [ 1, 2, 3, 4 ]
Count: 2
Millennium:
Stage:
value: 1
option: [ 1, 2, 3, 4 ]
Count: 2
TacticalChallenge:
PlayerSelect:
value: 0
@@ -141,15 +99,3 @@ ItemStorage:
stored: StoredInt
order: 3
color: "#21befc"
BountyTicket:
stored: StoredBountyTicket
order: 4
color: "#94cb44"
ScrimmageTicket:
stored: StoredScrimmageTicket
order: 5
color: "#f86c6a"
TacticalChallengeTicket:
stored: StoredTacticalChallengeTicket
order: 6
color: "#7ac8e5"
-6
View File
@@ -13,12 +13,6 @@ Mail:
Circle:
Scheduler:
Enable: true
Bounty:
Scheduler:
Enable: true
Scrimmage:
Scheduler:
Enable: true
TacticalChallenge:
Scheduler:
Enable: true
-2
View File
@@ -14,8 +14,6 @@
"Cafe",
"Mail",
"Circle",
"Bounty",
"Scrimmage",
"TacticalChallenge",
"DataUpdate"
]
-39
View File
@@ -35,44 +35,5 @@
},
"order": 3,
"color": "#21befc"
},
"BountyTicket": {
"name": "BountyTicket",
"path": "DataUpdate.ItemStorage.BountyTicket",
"i18n": "ItemStorage.BountyTicket.name",
"stored": "StoredBountyTicket",
"attrs": {
"time": "2020-01-01 00:00:00",
"total": 6,
"value": 0
},
"order": 4,
"color": "#94cb44"
},
"ScrimmageTicket": {
"name": "ScrimmageTicket",
"path": "DataUpdate.ItemStorage.ScrimmageTicket",
"i18n": "ItemStorage.ScrimmageTicket.name",
"stored": "StoredScrimmageTicket",
"attrs": {
"time": "2020-01-01 00:00:00",
"total": 6,
"value": 0
},
"order": 5,
"color": "#f86c6a"
},
"TacticalChallengeTicket": {
"name": "TacticalChallengeTicket",
"path": "DataUpdate.ItemStorage.TacticalChallengeTicket",
"i18n": "ItemStorage.TacticalChallengeTicket.name",
"stored": "StoredTacticalChallengeTicket",
"attrs": {
"time": "2020-01-01 00:00:00",
"total": 5,
"value": 0
},
"order": 6,
"color": "#7ac8e5"
}
}
-12
View File
@@ -29,18 +29,6 @@ Daily:
- Scheduler
Circle:
- Scheduler
Bounty:
- Scheduler
- Bounty
- Highway
- DesertRailroad
- Schoolhouse
Scrimmage:
- Scheduler
- Scrimmage
- Trinity
- Gehenna
- Millennium
TacticalChallenge:
- Scheduler
- TacticalChallenge
+13
View File
@@ -499,6 +499,19 @@ class AzurLaneConfig(ConfigUpdater, ManualConfig, GeneratedConfig, ConfigWatcher
self.task_call('DailyQuest')
self.task_stop()
def update_battle_pass_quests(self):
"""
Raises:
TaskEnd: Call task `BattlePass` and stop current task
"""
if self.stored.BattlePassTodayQuest.is_expired():
if self.stored.BattlePassLevel.is_full():
logger.info('BattlePassLevel full, no updates')
else:
logger.info('BattlePassTodayQuest expired, call task to update')
self.task_call('BattlePass')
self.task_stop()
@property
def DEVICE_SCREENSHOT_METHOD(self):
return self.Emulator_ScreenshotMethod
+2 -35
View File
@@ -17,8 +17,8 @@ class GeneratedConfig:
# Group `Emulator`
Emulator_Serial = 'auto'
Emulator_PackageName = 'auto' # auto, JP-Official, OVERSEA-Global
Emulator_GameLanguage = 'auto' # auto, jp, en
Emulator_PackageName = 'auto' # auto, JP-Official
Emulator_GameLanguage = 'auto' # auto, jp
Emulator_ScreenshotMethod = 'auto' # auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, scrcpy
Emulator_ControlMethod = 'MaaTouch' # minitouch, MaaTouch
Emulator_AdbRestart = False
@@ -45,36 +45,6 @@ class GeneratedConfig:
Cafe_AutoAdjust = True
Cafe_SecondCafe = True
# Group `Bounty`
Bounty_OnError = 'skip' # stop, skip
# Group `Highway`
Highway_Stage = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
Highway_Count = 2
# Group `DesertRailroad`
DesertRailroad_Stage = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
DesertRailroad_Count = 2
# Group `Schoolhouse`
Schoolhouse_Stage = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
Schoolhouse_Count = 2
# Group `Scrimmage`
Scrimmage_OnError = 'skip' # stop, skip
# Group `Trinity`
Trinity_Stage = 1 # 1, 2, 3, 4
Trinity_Count = 2
# Group `Gehenna`
Gehenna_Stage = 1 # 1, 2, 3, 4
Gehenna_Count = 2
# Group `Millennium`
Millennium_Stage = 1 # 1, 2, 3, 4
Millennium_Count = 2
# Group `TacticalChallenge`
TacticalChallenge_PlayerSelect = 0 # 0, 1, 2, 3
@@ -82,6 +52,3 @@ class GeneratedConfig:
ItemStorage_AP = {}
ItemStorage_Credit = {}
ItemStorage_Pyroxene = {}
ItemStorage_BountyTicket = {}
ItemStorage_ScrimmageTicket = {}
ItemStorage_TacticalChallengeTicket = {}
+1 -2
View File
@@ -8,8 +8,7 @@ class ManualConfig:
SCHEDULER_PRIORITY = """
Restart
> Cafe > Circle > Mail > DataUpdate > Bounty
> Scrimmage > TacticalChallenge
> Cafe > Circle > Mail > DataUpdate > TacticalChallenge
"""
"""
+1 -2
View File
@@ -458,8 +458,7 @@ class ConfigUpdater:
value = deep_get(old, keys=keys, default=data['value'])
typ = data['type']
display = data.get('display')
if (is_template or value is None or value == ''
or typ in ['lock', 'state'] or (display == 'hide' and typ != 'stored')):
if is_template or value is None or value == '' or typ == 'lock' or (display == 'hide' and typ != 'stored'):
value = data['value']
value = parse_value(value, data=data)
deep_set(new, keys=keys, value=value)
+6 -175
View File
@@ -30,14 +30,6 @@
"name": "Club",
"help": ""
},
"Bounty": {
"name": "Bounty",
"help": ""
},
"Scrimmage": {
"name": "Scrimmage",
"help": ""
},
"TacticalChallenge": {
"name": "Tactical Challenge",
"help": ""
@@ -84,21 +76,19 @@
"name": "Game Server",
"help": "Can't distinguish different regions of oversea servers, please select the server manually.",
"auto": "Auto-detect",
"JP-Official": "[JP]-Official",
"OVERSEA-Global": "[OVERSEA]-Global"
"JP-Official": "[JP]-Official"
},
"GameLanguage": {
"name": "In-game Text Language",
"help": "",
"help": "Currently, only Simplified Chinese and English are supported. Please set the text language in game to one of them.",
"auto": "Auto-detect",
"jp": "Japanese",
"en": "English"
"jp": "Japanese"
},
"ScreenshotMethod": {
"name": "Screenshot Method",
"help": "When using auto-select, a benchmark will be performed and automatically changed to the fastest screenshot method.\nGeneral speed: DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB.\nRun Tools - Performance Test to find the fastest method.",
"auto": "Auto-select the fastest",
"ADB": "ADB",
"ADB": "ADB ",
"ADB_nc": "ADB_nc",
"uiautomator2": "uiautomator2",
"aScreenCap": "aScreenCap",
@@ -213,155 +203,8 @@
"help": "Auto adjust cafe interface for better student interaction"
},
"SecondCafe": {
"name": "Second Floor",
"help": "JP server only\nEnable auto switch to second floor and perform interaction"
}
},
"Bounty": {
"_info": {
"name": "Bounty Settings",
"help": ""
},
"OnError": {
"name": "Error Handling",
"help": "Perform the selected action when an error occurs (ticket not enough or any invalid setting)",
"stop": "Stop script",
"skip": "Skip current task"
}
},
"Highway": {
"_info": {
"name": "Overpass",
"help": ""
},
"Stage": {
"name": "Select Stage",
"help": "",
"1": "01 - Overpass A",
"2": "02 - Overpass B",
"3": "03 - Overpass C",
"4": "04 - Overpass D",
"5": "05 - Overpass E",
"6": "06 - Overpass F",
"7": "07 - Overpass G",
"8": "08 - Overpass H",
"9": "09 - Overpass I"
},
"Count": {
"name": "Sweep X times",
"help": "Sweep the selected stage for X times"
}
},
"DesertRailroad": {
"_info": {
"name": "Desert Railroad",
"help": ""
},
"Stage": {
"name": "Select Stage",
"help": "",
"1": "01 - Abandoned Train A",
"2": "02 - Abandoned Train B",
"3": "03 - Abandoned Train C",
"4": "04 - Abandoned Train D",
"5": "05 - Abandoned Train E",
"6": "06 - Abandoned Train F",
"7": "07 - Abandoned Train G",
"8": "08 - Abandoned Train H",
"9": "09 - Abandoned Train I"
},
"Count": {
"name": "Sweep X times",
"help": "Sweep the selected stage for X times"
}
},
"Schoolhouse": {
"_info": {
"name": "Classroom",
"help": ""
},
"Stage": {
"name": "Select Stage",
"help": "",
"1": "01 - Besieged Classroom A",
"2": "02 - Besieged Classroom B",
"3": "03 - Besieged Classroom C",
"4": "04 - Besieged Classroom D",
"5": "05 - Besieged Classroom E",
"6": "06 - Besieged Classroom F",
"7": "07 - Besieged Classroom G",
"8": "08 - Besieged Classroom H",
"9": "09 - Besieged Classroom I"
},
"Count": {
"name": "Sweep X times",
"help": "Sweep the selected stage for X times"
}
},
"Scrimmage": {
"_info": {
"name": "Scrimmage Settings",
"help": ""
},
"OnError": {
"name": "Error Handling",
"help": "Perform the selected action when an error occurs (ticket not enough or any invalid setting)",
"stop": "Stop script",
"skip": "Skip current task"
}
},
"Trinity": {
"_info": {
"name": "Trinity",
"help": ""
},
"Stage": {
"name": "Select Stage",
"help": "",
"1": "01 - Trinity A",
"2": "02 - Trinity B",
"3": "03 - Trinity C",
"4": "04 - Trinity D"
},
"Count": {
"name": "Sweep X times",
"help": "Sweep the selected stage for X times"
}
},
"Gehenna": {
"_info": {
"name": "Gehenna",
"help": ""
},
"Stage": {
"name": "Select Stage",
"help": "",
"1": "01 - Gehenna A",
"2": "02 - Gehenna B",
"3": "03 - Gehenna C",
"4": "04 - Gehenna D"
},
"Count": {
"name": "Sweep X times",
"help": "Sweep the selected stage for X times"
}
},
"Millennium": {
"_info": {
"name": "Millennium",
"help": ""
},
"Stage": {
"name": "Select Stage",
"help": "",
"1": "01 - Millennium A",
"2": "02 - Millennium B",
"3": "03 - Millennium C",
"4": "04 - Millennium D"
},
"Count": {
"name": "Sweep X times",
"help": "Sweep the selected stage for X times"
"name": "Second Cafe",
"help": "Enable auto switch to second cafe and perform interaction"
}
},
"TacticalChallenge": {
@@ -394,18 +237,6 @@
"Pyroxene": {
"name": "Pyroxene",
"help": ""
},
"BountyTicket": {
"name": "Bounty",
"help": ""
},
"ScrimmageTicket": {
"name": "Scrimmage",
"help": ""
},
"TacticalChallengeTicket": {
"name": "Tactical Challenge",
"help": ""
}
},
"Gui": {
+3 -172
View File
@@ -30,14 +30,6 @@
"name": "公会",
"help": "社团 / 小组"
},
"Bounty": {
"name": "悬赏通缉",
"help": ""
},
"Scrimmage": {
"name": "学院交流会",
"help": ""
},
"TacticalChallenge": {
"name": "战术对抗赛",
"help": "战术大赛 / 竞技场"
@@ -84,15 +76,13 @@
"name": "游戏服务器",
"help": "无法区分国际服的不同地区,请手动选择服务器",
"auto": "自动检测",
"JP-Official": "[日服]-官服",
"OVERSEA-Global": "[国际服]-全球"
"JP-Official": "[日服]-官服"
},
"GameLanguage": {
"name": "游戏内文本语言",
"help": "",
"auto": "自动检测",
"jp": "日语",
"en": "英语"
"jp": "日语"
},
"ScreenshotMethod": {
"name": "模拟器截图方案",
@@ -214,154 +204,7 @@
},
"SecondCafe": {
"name": "第二咖啡厅",
"help": "仅支持日服\n自动切换第二咖啡厅进行互动点击"
}
},
"Bounty": {
"_info": {
"name": "悬赏通缉设置",
"help": ""
},
"OnError": {
"name": "错误处理",
"help": "当出现票券不足或设置有误等错误时,执行该操作",
"stop": "停止脚本运行",
"skip": "跳过当前任务"
}
},
"Highway": {
"_info": {
"name": "高架公路",
"help": ""
},
"Stage": {
"name": "选择关卡",
"help": "",
"1": "01 - 高架公路 A",
"2": "02 - 高架公路 B",
"3": "03 - 高架公路 C",
"4": "04 - 高架公路 D",
"5": "05 - 高架公路 E",
"6": "06 - 高架公路 F",
"7": "07 - 高架公路 G",
"8": "08 - 高架公路 H",
"9": "09 - 高架公路 I"
},
"Count": {
"name": "扫荡次数",
"help": "扫荡所选择关卡 X 次"
}
},
"DesertRailroad": {
"_info": {
"name": "沙漠铁路",
"help": ""
},
"Stage": {
"name": "选择关卡",
"help": "",
"1": "01 - 被遗弃的列车 A",
"2": "02 - 被遗弃的列车 B",
"3": "03 - 被遗弃的列车 C",
"4": "04 - 被遗弃的列车 D",
"5": "05 - 被遗弃的列车 E",
"6": "06 - 被遗弃的列车 F",
"7": "07 - 被遗弃的列车 G",
"8": "08 - 被遗弃的列车 H",
"9": "09 - 被遗弃的列车 I"
},
"Count": {
"name": "扫荡次数",
"help": "扫荡所选择关卡 X 次"
}
},
"Schoolhouse": {
"_info": {
"name": "教室",
"help": ""
},
"Stage": {
"name": "选择关卡",
"help": "",
"1": "01 - 被袭击的教室 A",
"2": "02 - 被袭击的教室 B",
"3": "03 - 被袭击的教室 C",
"4": "04 - 被袭击的教室 D",
"5": "05 - 被袭击的教室 E",
"6": "06 - 被袭击的教室 F",
"7": "07 - 被袭击的教室 G",
"8": "08 - 被袭击的教室 H",
"9": "09 - 被袭击的教室 I"
},
"Count": {
"name": "扫荡次数",
"help": "扫荡所选择关卡 X 次"
}
},
"Scrimmage": {
"_info": {
"name": "学院交流会设置",
"help": ""
},
"OnError": {
"name": "错误处理",
"help": "当出现票券不足或设置有误等错误时,执行该操作",
"stop": "停止脚本运行",
"skip": "跳过当前任务"
}
},
"Trinity": {
"_info": {
"name": "三一",
"help": ""
},
"Stage": {
"name": "选择关卡",
"help": "",
"1": "01 - 三一 A",
"2": "02 - 三一 B",
"3": "03 - 三一 C",
"4": "04 - 三一 D"
},
"Count": {
"name": "扫荡次数",
"help": "扫荡所选择关卡 X 次"
}
},
"Gehenna": {
"_info": {
"name": "格黑娜",
"help": ""
},
"Stage": {
"name": "选择关卡",
"help": "",
"1": "01 - 格黑娜 A",
"2": "02 - 格黑娜 B",
"3": "03 - 格黑娜 C",
"4": "04 - 格黑娜 D"
},
"Count": {
"name": "扫荡次数",
"help": "扫荡所选择关卡 X 次"
}
},
"Millennium": {
"_info": {
"name": "千年",
"help": ""
},
"Stage": {
"name": "选择关卡",
"help": "",
"1": "01 - 千年 A",
"2": "02 - 千年 B",
"3": "03 - 千年 C",
"4": "04 - 千年 D"
},
"Count": {
"name": "扫荡次数",
"help": "扫荡所选择关卡 X 次"
"help": "自动切换第二咖啡厅进行互动点击"
}
},
"TacticalChallenge": {
@@ -394,18 +237,6 @@
"Pyroxene": {
"name": "青辉石",
"help": ""
},
"BountyTicket": {
"name": "悬赏通缉",
"help": ""
},
"ScrimmageTicket": {
"name": "学院交流会",
"help": ""
},
"TacticalChallengeTicket": {
"name": "战术对抗赛",
"help": ""
}
},
"Gui": {
+2 -3
View File
@@ -5,10 +5,9 @@ Use 'import module.config.server as server' to import, don't use 'from xxx impor
lang = 'jp' # Setting default to cn, will avoid errors when using dev_tools
server = 'JP-Official'
VALID_LANG = ['jp', 'en']
VALID_LANG = ['jp']
VALID_SERVER = {
'JP-Official': 'com.YostarJP.BlueArchive',
'OVERSEA-Global': 'com.nexon.bluearchive',
'JP-Official': 'com.YostarJP.BlueArchive'
}
VALID_PACKAGE = set(list(VALID_SERVER.values()))
-16
View File
@@ -3,8 +3,6 @@ from functools import cached_property as functools_cached_property
from module.base.decorator import cached_property
from module.config.utils import DEFAULT_TIME, deep_get, get_server_last_monday_update, get_server_last_update
# from module.exception import ScriptError
@@ -175,20 +173,6 @@ class StoredCounter(StoredBase):
class StoredAP(StoredCounter):
pass
class StoredBountyTicket(StoredCounter, StoredExpiredAt0400):
FIXED_TOTAL = 6
pass
class StoredScrimmageTicket(StoredCounter, StoredExpiredAt0400):
FIXED_TOTAL = 6
class StoredTacticalChallengeTicket(StoredCounter, StoredExpiredAt0400):
FIXED_TOTAL = 5
# class StoredDailyActivity(StoredCounter, StoredExpiredAt0400):
# FIXED_TOTAL = 500
#
+4 -6
View File
@@ -1,9 +1,10 @@
from module.config.stored.classes import (
StoredAP,
StoredBountyTicket,
StoredBase,
StoredCounter,
StoredExpiredAt0400,
StoredExpiredAtMonday0400,
StoredInt,
StoredScrimmageTicket,
StoredTacticalChallengeTicket,
)
@@ -14,6 +15,3 @@ class StoredGenerated:
AP = StoredAP("DataUpdate.ItemStorage.AP")
Credit = StoredInt("DataUpdate.ItemStorage.Credit")
Pyroxene = StoredInt("DataUpdate.ItemStorage.Pyroxene")
BountyTicket = StoredBountyTicket("DataUpdate.ItemStorage.BountyTicket")
ScrimmageTicket = StoredScrimmageTicket("DataUpdate.ItemStorage.ScrimmageTicket")
TacticalChallengeTicket = StoredTacticalChallengeTicket("DataUpdate.ItemStorage.TacticalChallengeTicket")
-1
View File
@@ -13,7 +13,6 @@ from module.config.atomicwrites import atomic_write
LANGUAGES = ['zh-CN', 'en-US']
SERVER_TO_TIMEZONE = {
'JP-Official': timedelta(hours=9),
'OVERSEA-Global': timedelta(hours=0),
}
DEFAULT_TIME = datetime(2020, 1, 1, 0, 0)
+3 -3
View File
@@ -863,8 +863,8 @@ class Connection(ConnectionAttr):
# Auto package detection
if len(packages) == 0:
logger.critical(f'No Blue Archive package found, '
f'please confirm Blue Archive has been installed on device "{self.serial}"')
logger.critical(f'No Star Rail package found, '
f'please confirm Star Rail has been installed on device "{self.serial}"')
raise RequestHumanTakeover
if len(packages) == 1:
logger.info('Auto package detection found only one package, using it')
@@ -877,6 +877,6 @@ class Connection(ConnectionAttr):
# set_server(self.package)
else:
logger.critical(
f'Multiple Blue Archive packages found, auto package detection cannot decide which to choose, '
f'Multiple Star Rail packages found, auto package detection cannot decide which to choose, '
'please copy one of the available devices listed above to Alas.Emulator.PackageName')
raise RequestHumanTakeover

Some files were not shown because too many files have changed in this diff Show More